<commit_before>/**
 * Phase 07 - Create an OpenGL Context.
 *
 * The main goal of this phase is to see if it makes sense to structure the Xlib
 * code without the OpenGL code, or if they are married together.
 *
 * This code won't be structured very well, just trying to get stuff working.
 */
#include <errno.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

// ~16.6 ms between frames is ~60 fps.
#define RATE_LIMIT 16.6

#define _NET_WM_STATE_TOGGLE 2

// OpenGL Attribute list for double buffer.
static int attr_list_double[] = {
  GLX_RGBA,       GLX_DOUBLEBUFFER,
  GLX_RED_SIZE,   4,
  GLX_GREEN_SIZE, 4,
  GLX_BLUE_SIZE,  4,
  GLX_DEPTH_SIZE, 16,
  None,
};

// OpenGL Attribute list for non double buffer (single buffer?).
static int attr_list_single[] = {
  GLX_RGBA,
  GLX_RED_SIZE,   4,
  GLX_GREEN_SIZE, 4,
  GLX_BLUE_SIZE,  4,
  GLX_DEPTH_SIZE, 16,
  None,
};

// Forward declaration of this function so we can use it in main().
double timespec_diff(struct timespec *a, struct timespec *b);

int main(int argc, char *argv[])
{
  // Create application display.
  Display *dpy = XOpenDisplay(NULL);

  if (dpy == NULL) {
    return EXIT_FAILURE;
  }

  // Create the application Window.
  unsigned long black = BlackPixel(dpy, DefaultScreen(dpy));
  Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 800, 600, 0, black, black);

  // Setup the Window Manager hints.
  XWMHints *wmhints = XAllocWMHints();
  // This basically tells other functions that this contains a value for input and initial state.
  wmhints->flags = InputHint | StateHint;
  // And these are the values for input and initial state.
  wmhints->input = True;
  wmhints->initial_state = NormalState;

  // Setup the Size Hints (also for the Window Manager).
  XSizeHints *sizehints = XAllocSizeHints();
  // This tells other functions that the value for min width and height.
  sizehints->flags = PMinSize;
  // And these are the values for min width and height.
  sizehints->min_width = 400;
  sizehints->min_height = 300;

  /*
   * This particular function does some allocating that doesn't ever get freed.
   * Valgrind reports 27,262 bytes in 384 blocks as still reachable because of this.
   * It's possible that this "leak" could be avoided by using XSetWMProperties()
   * and creating our own XTextProperty's.
   */
  // Sets Window properties that are used by the Window Manager.
  Xutf8SetWMProperties(dpy, win, "Phase 01", "", NULL, 0, sizehints, wmhints, NULL);

  // Tell X that we want to be notified of the Exposure event, so we can know when our window is initially visible.
  XSelectInput(dpy, win, ExposureMask);

  // Grab a copy of X's representation of WM_PROTOCOLS, used in checking for window closed events.
  Atom wm_protocol = XInternAtom(dpy, "WM_PROTOCOLS", True);
  // Let the Window Manager know that we want the event when a user closes the window.
  Atom wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", True);
  XSetWMProtocols(dpy, win, &wm_delete, 1);

  // Map the window to the display.
  XMapWindow(dpy, win);

  // Start building the OpenGL Context.

  // We need to know if double buffering is available.
  Bool double_buffer = False;

  /**
   * So a lot of libraries don't care if they introduce memory leaks that are
   * still reachable. From what I've read online, if it's still reachable, then
   * that typically means the leak is known and isn't something that gets out of control.
   * If you were to generate that sort of a leak in a big ol' loop, then the leaks
   * would likely become definitely lost (the bad kind of memory leak).
   *
   * Anyways, glXChooseVisual() introduces more reachable leaks *sigh*.
   * Valgrind 5,636 bytes in 17 blocks that are still reachable.
   */
  // Get the Visual Info for a double buffered OpenGL Context.
  XVisualInfo *vi = NULL;
  vi = glXChooseVisual(dpy, DefaultScreen(dpy), attr_list_double);

  if (vi == NULL) {
    // If we failed to get double buffered info, get the single buffered info.
    vi = glXChooseVisual(dpy, DefaultScreen(dpy), attr_list_single);
    double_buffer = False;
    printf("Single Buffered rendering will be used, no double buffering available\n");
  } else {
    // Double buffer was a valid choice.
    double_buffer = True;
    printf("Double Buffered rendering available\n");
  }

  // Create the OpenGL Context
  GLXContext opengl_context;
  opengl_context = glXCreateContext(dpy, vi, NULL, True);

  // Set the new OpenGL Context as the Current OpenGL context.
  glXMakeCurrent(dpy, win, opengl_context);

  // Check if direct rendering is enabled.
  if (glXIsDirect(dpy, opengl_context)) {
    printf("Direct Rendering enabled\n");
  } else {
    printf("No Direct Rendering available\n");
  }

  // Free up the Visual Info after we're done creating the OpenGL context.
  XFree(vi);
  vi = NULL;

  // This variable will be used to examine events thrown to our application window.
  XEvent e;

  // Block execution until the window is exposed.
  XWindowEvent(dpy, win, ExposureMask, &e);

  // After being exposed, we'll tell X what input events we want to know about here.
  XSelectInput(dpy, win, KeyPressMask);

  // The loop
  // @TODO: Use sleeping to avoid taking up all CPU cycles.
  Bool done = False;

  // We need to track very small periods of time (nanoseconds), so we use the struct timespec.
  struct timespec prev, curr;

  /*
   * Get the current time with CLOCK_MONOTONIC_RAW, which gets the time past since a certain time.
   * CLOCK_MONOTONIC_RAW is not subject to adjustments to the system clock.
   */
  clock_gettime(CLOCK_MONOTONIC_RAW, &curr);<commit_msg>Check which OpenGL version we're running<commit_after>/**
 * Phase 07 - Create an OpenGL Context.
 *
 * The main goal of this phase is to see if it makes sense to structure the Xlib
 * code without the OpenGL code, or if they are married together.
 *
 * This code won't be structured very well, just trying to get stuff working.
 */
#include <errno.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

// ~16.6 ms between frames is ~60 fps.
#define RATE_LIMIT 16.6

#define _NET_WM_STATE_TOGGLE 2

// OpenGL Attribute list for double buffer.
static int attr_list_double[] = {
  GLX_RGBA,       GLX_DOUBLEBUFFER,
  GLX_RED_SIZE,   4,
  GLX_GREEN_SIZE, 4,
  GLX_BLUE_SIZE,  4,
  GLX_DEPTH_SIZE, 16,
  None,
};

// OpenGL Attribute list for non double buffer (single buffer?).
static int attr_list_single[] = {
  GLX_RGBA,
  GLX_RED_SIZE,   4,
  GLX_GREEN_SIZE, 4,
  GLX_BLUE_SIZE,  4,
  GLX_DEPTH_SIZE, 16,
  None,
};

// Forward declaration of this function so we can use it in main().
double timespec_diff(struct timespec *a, struct timespec *b);

int main(int argc, char *argv[])
{
  // Create application display.
  Display *dpy = XOpenDisplay(NULL);

  if (dpy == NULL) {
    return EXIT_FAILURE;
  }

  // Create the application Window.
  unsigned long black = BlackPixel(dpy, DefaultScreen(dpy));
  Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 800, 600, 0, black, black);

  // Setup the Window Manager hints.
  XWMHints *wmhints = XAllocWMHints();
  // This basically tells other functions that this contains a value for input and initial state.
  wmhints->flags = InputHint | StateHint;
  // And these are the values for input and initial state.
  wmhints->input = True;
  wmhints->initial_state = NormalState;

  // Setup the Size Hints (also for the Window Manager).
  XSizeHints *sizehints = XAllocSizeHints();
  // This tells other functions that the value for min width and height.
  sizehints->flags = PMinSize;
  // And these are the values for min width and height.
  sizehints->min_width = 400;
  sizehints->min_height = 300;

  /*
   * This particular function does some allocating that doesn't ever get freed.
   * Valgrind reports 27,262 bytes in 384 blocks as still reachable because of this.
   * It's possible that this "leak" could be avoided by using XSetWMProperties()
   * and creating our own XTextProperty's.
   */
  // Sets Window properties that are used by the Window Manager.
  Xutf8SetWMProperties(dpy, win, "Phase 01", "", NULL, 0, sizehints, wmhints, NULL);

  // Tell X that we want to be notified of the Exposure event, so we can know when our window is initially visible.
  XSelectInput(dpy, win, ExposureMask);

  // Grab a copy of X's representation of WM_PROTOCOLS, used in checking for window closed events.
  Atom wm_protocol = XInternAtom(dpy, "WM_PROTOCOLS", True);
  // Let the Window Manager know that we want the event when a user closes the window.
  Atom wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", True);
  XSetWMProtocols(dpy, win, &wm_delete, 1);

  // Map the window to the display.
  XMapWindow(dpy, win);

  // Start building the OpenGL Context.

  // We need to know if double buffering is available.
  Bool double_buffer = False;

  /**
   * So a lot of libraries don't care if they introduce memory leaks that are
   * still reachable. From what I've read online, if it's still reachable, then
   * that typically means the leak is known and isn't something that gets out of control.
   * If you were to generate that sort of a leak in a big ol' loop, then the leaks
   * would likely become definitely lost (the bad kind of memory leak).
   *
   * Anyways, glXChooseVisual() introduces more reachable leaks *sigh*.
   * Valgrind 5,636 bytes in 17 blocks that are still reachable.
   */
  // Get the Visual Info for a double buffered OpenGL Context.
  XVisualInfo *vi = NULL;
  vi = glXChooseVisual(dpy, DefaultScreen(dpy), attr_list_double);

  if (vi == NULL) {
    // If we failed to get double buffered info, get the single buffered info.
    vi = glXChooseVisual(dpy, DefaultScreen(dpy), attr_list_single);
    double_buffer = False;
    printf("Single Buffered rendering will be used, no double buffering available\n");
  } else {
    // Double buffer was a valid choice.
    double_buffer = True;
    printf("Double Buffered rendering available\n");
  }

  // Create the OpenGL Context
  GLXContext opengl_context;
  opengl_context = glXCreateContext(dpy, vi, NULL, True);

  // Set the new OpenGL Context as the Current OpenGL context.
  glXMakeCurrent(dpy, win, opengl_context);

  // Check if direct rendering is enabled.
  if (glXIsDirect(dpy, opengl_context)) {
    printf("Direct Rendering enabled\n");
  } else {
    printf("No Direct Rendering available\n");
  }

  // Print out the version (Should be used at some point to restrict running to > 4.0).
  printf("OpenGL Version: %s\n", glGetString(GL_VERSION));
  printf("OpenGL Shading Language Verison: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));

  // Free up the Visual Info after we're done creating the OpenGL context.
  XFree(vi);
  vi = NULL;

  // This variable will be used to examine events thrown to our application window.
  XEvent e;

  // Block execution until the window is exposed.
  XWindowEvent(dpy, win, ExposureMask, &e);

  // After being exposed, we'll tell X what input events we want to know about here.
  XSelectInput(dpy, win, KeyPressMask);

  // The loop
  // @TODO: Use sleeping to avoid taking up all CPU cycles.
  Bool done = False;

  // We need to track very small periods of time (nanoseconds), so we use the struct timespec.
  struct timespec prev, curr;

  /*
   * Get the current time with CLOCK_MONOTONIC_RAW, which gets the time past since a certain time.
   * CLOCK_MONOTONIC_RAW is not subject to adjustments to the system clock.
   */
  clock_gettime(CLOCK_MONOTONIC_RAW, &curr);
{'fraction_non_alphanumeric': 0.08963633259347789, 'fraction_numerical': 0.010244152296397474, 'mean_word_length': 3.5583657587548636, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4995714', 'n_tokens_mistral': 3872, 'n_tokens_neox': 3644, 'n_words': 1471}