/* xscreensaver, Copyright © 1991-2022 Jamie Zawinski <jwz@jwz.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.  No representations are made about the suitability of this
 * software for any purpose.  It is provided "as is" without express or 
 * implied warranty.
 */

/* Some random diagnostics printed in -verbose mode about what extensions
   are available on the server, and their version numbers.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#ifndef HAVE_XINPUT
# error The XInput2 extension is required
#endif

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
#include <X11/Intrinsic.h>

#include <X11/extensions/XInput2.h>

#ifdef HAVE_XSHM_EXTENSION
# include <X11/extensions/XShm.h>
#endif /* HAVE_XSHM_EXTENSION */

#ifdef HAVE_DPMS_EXTENSION
# include <X11/extensions/dpms.h>
#endif /* HAVE_DPMS_EXTENSION */


#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
# include <X11/extensions/Xdbe.h>
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */

#ifdef HAVE_XF86VMODE
# include <X11/extensions/xf86vmode.h>
#endif /* HAVE_XF86VMODE */

#ifdef HAVE_XINERAMA
# include <X11/extensions/Xinerama.h>
#endif /* HAVE_XINERAMA */

#ifdef HAVE_RANDR
# include <X11/extensions/Xrandr.h>
#endif /* HAVE_RANDR */

#ifdef HAVE_XCOMPOSITE_EXTENSION
# include <X11/extensions/Xcomposite.h>
#endif

#ifdef HAVE_XKB
# include <X11/XKBlib.h>
#endif

#include "xscreensaver.h"


void
print_available_extensions (saver_info *si)
{
  int i, j;
  static struct {
    const char *name; const char *desc; 
    Bool useful_p;
    Status (*version_fn) (Display *, int *majP, int *minP);
  } exts[] = {

# if 0
   { "MIT-SCREEN-SAVER",                        "MIT Screen-Saver",
        False, 0
   },
# endif
   { "MIT-SHM",                                 "Shared Memory",
#     ifdef HAVE_XSHM_EXTENSION
        True, (Status (*) (Display*,int*,int*)) XShmQueryVersion /* 4 args */
#     else
        False, 0
#     endif
   }, { "DOUBLE-BUFFER",                        "Double-Buffering",
#     ifdef HAVE_DOUBLE_BUFFER_EXTENSION
        True, XdbeQueryExtension
#     else
        False, 0
#     endif
   }, { "DPMS",                                 "Power Management",
#     ifdef HAVE_DPMS_EXTENSION
        True,  DPMSGetVersion
#     else
        False, 0
#     endif
   }, { "GLX",                                  "GLX",
#     ifdef HAVE_GL
        True,  0
#     else
        False, 0
#     endif
   }, { "XFree86-VidModeExtension",             "XF86 Video-Mode",
#     ifdef HAVE_XF86VMODE
        True,  XF86VidModeQueryVersion
#     else
        False, 0
#     endif
   }, { "XC-VidModeExtension",                  "XC Video-Mode",
#     ifdef HAVE_XF86VMODE
        True,  XF86VidModeQueryVersion
#     else
        False, 0
#     endif
   }, { "XINERAMA",                             "Xinerama",
#     ifdef HAVE_XINERAMA
        True,  XineramaQueryVersion
#     else
        False, 0
#     endif
   }, { "RANDR",                                "Resize-and-Rotate",
#     ifdef HAVE_RANDR
        True,  XRRQueryVersion
#     else
        False, 0
#     endif
   }, { "Composite",                            "Composite",
#     ifdef HAVE_XCOMPOSITE_EXTENSION
        True,  XCompositeQueryVersion
#     else
        True, 0
#     endif
   }, { "XKEYBOARD",                            "XKeyboard",
#     ifdef HAVE_XKB
        True,  0,
#     else
        False, 0
#     endif
   }, { "DRI",			"DRI",		True, 0
   }, { "NV-CONTROL",		"NVidia",	True, 0
   }, { "NV-GLX",		"NVidia GLX",	True, 0
   }, { "Apple-DRI",		"Apple-DRI",	True, 0
   }, { "Apple-WM",		"Apple-WM",	True, 0
   }, { "XInputExtension",	"XInput",	True, 0
   },
  };

  fprintf (stderr, "%s: running on display \"%s\"\n", blurb(), 
           DisplayString(si->dpy));
  fprintf (stderr, "%s: vendor is %s, %d\n", blurb(),
	   ServerVendor(si->dpy), VendorRelease(si->dpy));

  fprintf (stderr, "%s: useful extensions:\n", blurb());
  for (i = 0; i < countof(exts); i++)
    {
      int op = 0, event = 0, error = 0;
      char buf [255];
      int maj = 0, min = 0;
      int dummy1, dummy2, dummy3;

      /* Most of the extension version functions take 3 args,
         writing results into args 2 and 3, but some take more.
         We only ever care about the first two results, but we
         pass in three extra pointers just in case.
       */
      Status (*version_fn_2) (Display*,int*,int*,int*,int*,int*) =
        (Status (*) (Display*,int*,int*,int*,int*,int*)) exts[i].version_fn;

      if (!XQueryExtension (si->dpy, exts[i].name, &op, &event, &error))
        continue;
      sprintf (buf, "%s:   ", blurb());
      strcat (buf, exts[i].desc);

      if (!strcmp (exts[i].desc, "XInput"))
        {
          int maj = 999, min = 999;              /* Desired */
          XIQueryVersion (si->dpy, &maj, &min);  /* Actual */
          sprintf (buf+strlen(buf), " (%d.%d)", maj, min);
        }
      else if (!version_fn_2)
        ;
      else if (version_fn_2 (si->dpy, &maj, &min, &dummy1, &dummy2, &dummy3))
        sprintf (buf+strlen(buf), " (%d.%d)", maj, min);
      else
        strcat (buf, " (unavailable)");

      if (!exts[i].useful_p)
        strcat (buf, " (disabled at compile time)");
      fprintf (stderr, "%s\n", buf);
    }

# ifdef HAVE_LIBSYSTEMD
  fprintf (stderr, "%s:   libsystemd\n", blurb());
# endif
# ifdef HAVE_LIBELOGIND
  fprintf (stderr, "%s:   libelogind\n", blurb());
# endif
# if !defined(HAVE_LIBSYSTEMD) && !defined(HAVE_LIBELOGIND)
  fprintf (stderr, "%s:   libsystemd/libelogind (disabled at compile time)\n",
           blurb());
# endif

  for (i = 0; i < si->nscreens; i++)
    {
      saver_screen_info *ssi = &si->screens[i];
      unsigned long colormapped_depths = 0;
      unsigned long non_mapped_depths = 0;
      XVisualInfo vi_in, *vi_out;
      int out_count;

      if (!ssi->real_screen_p) continue;

      vi_in.screen = ssi->real_screen_number;
      vi_out = XGetVisualInfo (si->dpy, VisualScreenMask, &vi_in, &out_count);
      if (!vi_out) continue;
      for (j = 0; j < out_count; j++) {
	if (vi_out[j].depth >= 32) continue;
	if (vi_out[j].class == PseudoColor)
	  colormapped_depths |= (1 << vi_out[j].depth);
	else
	  non_mapped_depths  |= (1 << vi_out[j].depth);
	}
      XFree ((char *) vi_out);

      if (colormapped_depths)
	{
	  fprintf (stderr, "%s: screen %d colormapped depths:", blurb(),
                   ssi->real_screen_number);
	  for (j = 0; j < 32; j++)
	    if (colormapped_depths & (1 << j))
	      fprintf (stderr, " %d", j);
	  fprintf (stderr, "\n");
	}
      if (non_mapped_depths)
	{
	  fprintf (stderr, "%s: screen %d non-colormapped depths:",
                   blurb(), ssi->real_screen_number);
	  for (j = 0; j < 32; j++)
	    if (non_mapped_depths & (1 << j))
	      fprintf (stderr, " %d", j);
	  fprintf (stderr, "\n");
	}
    }
}
