Blob Blame Raw
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <gtk/gtk.h>


const double pi = 3.141592653589793;

const guint interval_ms = 5;
const guint interval2_ms = 50;
const double G = 1000000;
const double radius = 30;

int width = 700;
int height = 500;

double mx = 0;
double my = 0;
double x = 200;
double y = 200;
double vx = 0;
double vy = 0;

GtkWidget *window;


gboolean motion(GtkWidget *widget, GdkEventMotion *event, gpointer data) {
  mx = event->x;
  my = event->y;
  return TRUE;
}

gboolean timeout(gpointer data) {
  double t = interval_ms/1000.0;

  double dx = mx - x;
  double dy = my - y;
  double d = sqrt(dx*dx + dy*dy);

  double ax = G*dx/(d*d*d);
  double ay = G*dy/(d*d*d);
  if (d < 10.0) ax = ay = 0.0;

  vx += ax*t;
  vy += ay*t;

  x += vx*t;
  y += vy*t;
  
  if (x < radius)
    { x = radius; vx = fabs(vx); }
  if (x > width - radius)
    { x = width - radius; vx = -fabs(vx); }
  if (y < radius)
    { y = radius; vy = fabs(vy); }
  if (y > height - radius)
    { y = height - radius; vy = -fabs(vy); }
  
  return TRUE;
}

gboolean timeout2(gpointer data) {
  gtk_widget_queue_draw(window);
  return TRUE;
}

gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer data) {
  cairo_set_source_rgba(cr, 0.9, 0.9, 0.9, 1);
  cairo_paint(cr);

  cairo_set_source_rgba(cr, 0, 0, 0, 1);
  cairo_set_line_width(cr, 1.0);
  cairo_arc(cr, x, y, radius, 0, 2*pi);
  cairo_stroke(cr);

  return TRUE;
}

void activate(GtkApplication* app, gpointer data) {
  window = gtk_application_window_new (app);
  g_signal_connect(window, "draw", G_CALLBACK(draw), NULL);
  g_signal_connect(window, "motion-notify-event", G_CALLBACK(motion), NULL);
  gtk_widget_add_events(window, GDK_POINTER_MOTION_MASK);
  gtk_window_set_default_size(GTK_WINDOW(window), width, height);
  gtk_widget_show_all(window);

  g_timeout_add(interval_ms, timeout, NULL);
  g_timeout_add(interval2_ms, timeout2, NULL);
}

int main(int argc, char **argv) {
  GtkApplication *application = gtk_application_new(NULL, 0);
  g_signal_connect(application, "activate", G_CALLBACK(activate), NULL);
  int status = g_application_run(G_APPLICATION(application), argc, argv);
  g_object_unref(application);
  return status;
}