[Cialug] GUI Programming
Zachary Kotlarek
zach at kotlarek.com
Fri Mar 8 01:57:15 CST 2013
On Mar 7, 2013, at 7:25 PM, Todd Walton <tdwalton at gmail.com> wrote:
> How am I supposed to know what's going on
> with this if there's nothing to indicate what's going on??
The part you aren't seeing is the "event loop". It used to be something you had to write yourself. As other have noted that loop is typically now part of whatever GUI framework you're using, and for many uses it's perfectly acceptable to let that framework be "magic" so long as you understand the API. It doesn't hurt to know how it works under the hood, but in most cases it won't help you write better code any more than understanding the sequencing of your spark plugs will make you a better driver.
--
For reference, here's a very crude explanation of what's happening under the hood:
The next level down is the GUI-level event loop. This is the bit you interact with via the API, where you link "button 7" or "x key pressed" to some function you wrote. Back in the day (circa 1990) you had to write this yourself. These days it's baked into the API that draws buttons and whatnot. It does something like this:
while (forever) {
input = waitForUserInput();
if (input->type == click) {
doubleClick = false;
if (lastClick > now() - system.config.doubleClickInterval) {
doubleClick = true;
}
lastClick = now();
if (doubleClick && input->x == 2) {
clickedInToolbar(input->y);
} else if (input->x == 22 && input->y == 44) {
buttonClicked("button7");
}
} else if (input->type == keyboard) {
if (input->modifiers->ctrl) {
ctrlKeyPressed(input->character);
} else {
keyPressed(input->character);
}
}
}
That GUI-level event loop itself depends on OS-level functions like waitForUserInput() and translations of hardware events into higher-level data. Even further back in the day (circa 1980) you had to write this yourself, but these days it's baked into the OS:
main() {
struct input = <various data>
setInterruptHandler(device.keyboard, keyboardHandler);
mousePoll();
}
waitForUserInput() {
waitForInterrupt(system.softwareInterrupt1);
markInterruptHandled(system.softwareInterrupt1);
return input
}
keyboardHandler() {
input.modifiers = device.keyboard.readModifiers();
input.character = device.keyboard.readKey();
input.type = keyboard;
markInterruptHandled(device.keyboard);
dispatchInterrupt(system.softwareInterrupt1);
}
mousePoll() {
markInterruptHandled(cpu.timer);
if (device.mouse.x != input.x || device.mouse.y != input.y) {
input.x = device.mouse.x;
input.y = device.mouse.y;
}
setInterruptHandler(cpu.timer, mousePoll);
dispatchInterrupt(cpu.timer, system.config.mousePollInterval);
}
That OS-level event loop depends on interrupts and other functions to interact with physical devices, which are provided by hardware and related drivers (both which may themselves have a layering of events/polls/etc. to provide the higher-level functionality).
So it's all "function-driven", it's just that we've abstracted the common use cases of unpredictable changes into things called "events" which make higher-level functions get called when specific changes occur in the computer system. And that happens repeatedly through a number of layers starting in actual physical devices and working its way up to your GUI layer.
But the whole point of the layering is that you don't really need to understand what's happening. In certain use cases it might be necessary or beneficial (if there are bugs in the framework, for example, or limitations that don't translate clearly into the API), but if you regularly have to delve into the implementation details of your framework to make it do what you want there's a good chance you're using it wrong, or using the wrong framework.
Zach
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 2746 bytes
Desc: not available
URL: <http://cialug.org/pipermail/cialug/attachments/20130307/c1b62610/attachment-0001.bin>
More information about the Cialug
mailing list