The flow of instructions in a GUI application is typically such that, after some initialization steps, a body of code called the '''event loop''' (or '''main loop''') is executed repeatedly, until the application terminates. Agar provides one trivial event loop routine ({{Fn|AG_EventLoop}}), which is suitable to most ordinary applications. It periodically updates the display, processes incoming events, and updates active timers. == Example code == The following code is taken from {{C|demos/customeventloop}}. The basic requirements for an event loop are: * Call {{Fn|AG_BeginRendering}} to prepare for rendering of GUI elements. * Invoke {{Fn|AG_WindowDraw}} to render visible windows (under framebuffer modes, video regions are not updated immediately.) * Call {{Fn|AG_EndRendering}} (under framebuffer modes, the video updates happen here.) * Look for events with {{Fn|AG_PendingEvents}}, retrieve them with {{Fn|AG_GetNextEvent}}, and possibly process them with {{Fn|AG_ProcessEvent}}. * Update its wheel of time by calling {{Fn|AG_ProcessTimeout}}. As an optimization, you only need to call the function if the macro {{Fn|AG_TIMEOUTS_QUEUED}} evaluates to 1. /* * This application demonstrates the use of a custom event loop. */ #include #include int pressedKey = 0; /* Last pressed key */ int xClick = 0, yClick = 0; /* Last clicked x,y */ int curFPS = 0; /* Measured frame rate */ const int nominalFPS = 1000/30; /* Nominal frame rate */ /* * Our custom event loop routine. */ static void MyEventLoop(void) { AG_Driver *drv; AG_Window *win; Uint32 t1, t2; AG_DriverEvent dev; t1 = AG_GetTicks(); for (;;) { t2 = AG_GetTicks(); if (t2-t1 >= nominalFPS) { /* * Case 1: Update the video display. */ AG_LockVFS(&agDrivers); /* Render the Agar windows */ if (agDriverSw) { /* With single-window drivers (e.g., sdlfb). */ AG_BeginRendering(agDriverSw); AG_FOREACH_WINDOW(win, agDriverSw) { AG_ObjectLock(win); AG_WindowDraw(win); AG_ObjectUnlock(win); } AG_EndRendering(agDriverSw); } else { /* With multiple-window drivers (e.g., glx). */ AGOBJECT_FOREACH_CHILD(drv, &agDrivers, ag_driver) { if (!AGDRIVER_MULTIPLE(drv)) { continue; } win = AGDRIVER_MW(drv)->win; if (win->visible) { AG_BeginRendering(drv); AG_ObjectLock(win); AG_WindowDraw(win); AG_ObjectUnlock(win); AG_EndRendering(drv); } } } AG_UnlockVFS(&agDrivers); t1 = AG_GetTicks(); curFPS = nominalFPS - (t1-t2); if (curFPS < 1) { curFPS = 1; } } else if (AG_PendingEvents(NULL) > 0) { /* * Case 2: There are events waiting to be processed. */ do { /* Retrieve the next queued event. */ if (AG_GetNextEvent(NULL, &dev) == 1) { switch (dev.type) { case AG_DRIVER_MOUSE_BUTTON_DOWN: xClick = dev.data.button.x; yClick = dev.data.button.y; printf("Click at %d,%d!\n", dev.data.button.x, dev.data.button.y); break; case AG_DRIVER_KEY_DOWN: pressedKey = (int)dev.data.key.ks; printf("Key down: %d (0x%x)\n", (int)dev.data.key.ks, (Uint)dev.data.key.ucs); break; default: break; } /* Forward the event to Agar. */ if (AG_ProcessEvent(NULL, &dev) == -1) return; } } while (AG_PendingEvents(NULL) > 0); } else if (AG_TIMEOUTS_QUEUED()) { /* * Case 3: There are AG_Timeout(3) callbacks to run. */ AG_ProcessTimeouts(t2); } else { /* * Case 4: Nothing to do, idle. */ AG_Delay(1); } } } int main(int argc, char *argv[]) { AG_Window *win; char *driverSpec = NULL, *optArg; int c; while ((c = AG_Getopt(argc, argv, "?hd:", &optArg, NULL)) != -1) { switch (c) { case 'd': driverSpec = optArg; break; case '?': case 'h': default: printf("Usage: customeventloop [-d agar-driver-spec]\n"); return (1); } } if (AG_InitCore("agar-customeventloop-demo", 0) == -1 || AG_InitGraphics(driverSpec) == -1) { fprintf(stderr, "%s\n", AG_GetError()); return (1); } AG_BindGlobalKey(AG_KEY_ESCAPE, AG_KEYMOD_ANY, AG_QuitGUI); win = AG_WindowNew(0); AG_WindowSetCaption(win, "Agar custom event loop demo"); AG_LabelNewPolled(win, AG_LABEL_EXPAND, "Testing custom event loop\n" "Frame rate = %d\n" "Pressed key = %d\n" "Clicked at %d,%d\n", &curFPS, &pressedKey, &xClick, &yClick); AG_ButtonNewFn(win, AG_BUTTON_HFILL, "Quit", AGWINDETACH(win)); AG_WindowSetGeometry(win, -1, -1, 300, 128); AG_WindowShow(win); MyEventLoop(); AG_Destroy(); return (0); } == SEE ALSO == * [[Video initialization]] * [[Setting Event Handlers]] * {{man3|AG_Event}}, {{man3|AG_Window}}, {{man3|AG_Driver}} [[Category:Tutorials]] [[Category:Agar-GUI]] [[Category:Agar-Core]]