Archive | Camera Module RSS for this section

DMP Photo Booth 1.0

Well, the day has come and gone. DMP Photo Booth’s final test on June 21st went off without issue, and DMP Photo Booth has left Beta and is now considered “production ready”. The initial 1.0 release can be found on GitHub.

The significance of June 21st is the very reason DMP Photo Booth was created; the 21st is the day of my wedding. My wife wanted a photo booth for the reception. We looked into renting a photo booth, but it turns out that they run around $1,000. I turned to open source. Some quick googling turned up some options, but they were all personal projects or out of date. Sure I could get somebody else’s project working, but what’s the fun in that? I decided that we didn’t need to rent one, or download one, I could build it!

In late 2013, I set to work in earnest. I had a couple of months of downtime in school, and since I’m not currently working it was the perfect time. I decided I had three main objectives for this project: get some arduino experience, get some GTK+ experience, and do this all as portably as possible. I had initially decided to mostly ignore GLib and focus on GTK, but slowly I grew to appreciate GLib for what it is: the standard library that C never had. First I used GModule to handle shared libraries in a portable manner. Next I decided to use GLib primitives to keep from having to deal with cross-platform type wonkiness. Next, having grown tired of dealing with return codes, I refactored the project to use GLib’s exception replacement: GError.

Lessons Learned

It’s not all roses and puppies though. There are certainly things I’d do differently. DMP Photo Booth is developed in an Object Oriented style, passing opaque structs with “method” functions that operate on them. Each component of the program are organized into their own source file with file scoped globals scattered throughout. Said globals are protected by mutexes to create a semblance of thread safety. That said, threading issues have been a major thorn in my side. Long story short: I regret this design choice. While I still feel that this is the correct way to structure C code, and that if globals are required, this is the correct way to handle them; I feel that I should have made more of an effort to limit side effects. Recently, I’ve spent some time doing functional programming, and if I could do it again I’d try to write in a more functional style. Fortunately for me, this is something that a little refactoring could help with.

Additionally, one thing I thought would be a major help is something that began to be a major thorn in my side: NetBeans. As the size of the project grew, NetBeans got slower and slower. It seemed that I spent more time fiddling with IDE settings than actually coding. Even worse is that the IDE-generated makefile is so convoluted that it’s extremely difficult to modify by hand in a satisfying way. I’ve always coded with and IDE so I wouldn’t have even considered not using one, but then I spent some time with Haskell. One of Haskell’s “problems” is that it doesn’t have good IDE support. It doesn’t seem like any IDE really handles it well, so most people use Emacs. Personally, I haven’t really warmed up to Emacs, but GEdit has syntax highlighting for Haskell and a built-in terminal for GHCI. GEdit also has syntax highlighting for C. Next time, I will seriously consider using a lighter-weight text editor for a C project. All this said, I think NetBeans for Java remains the way to go.

What’s Next

Like any program, version 1.0 is just one of many versions. There certainly remains a lot of work to do with DMP Photo Booth. Some major items you are likely to see whenever I get around to working on DMP Photo Booth some more:

Options Dialog

I think anybody who has seen it will agree: the options dialog in DMP Photo Booth is bad. It’s poorly organized, and kind of wonky. Personally, I modify settings using the .rc file, which is telling. This is certainly a high-priority improvement.

Functional Refactor

Like I said above, the code could use a pass to limit side effects. Funtions need to have their side effects limited, and globals need to be eliminated unless absolutely necessary. However, C is not a functional language. While one could argue that function pointers enable functional programming in C, this is a very pedantic argument. I won’t be going crazy with functional programming techniques. There will be no Monads, or for loops being turned into mappings of function pointers.

Optional Module API

An idea I’ve had on the back burner for a while is an optional module API. This would be used for very specific quality-of-life things. For instance, a module could provide a GTK widget to be shown in the options dialog. Any module that doesn’t want to implement any or all of the optional API can just ignore it. The module loading function will gracefully handle the dlsym failure, just treating it as it is: declining to implement the API. I have no plans to change the current existing API, so all you module developers can rest easy!

User Interface Module

It occurred to me that it might be good to have a UI module. This would provide the UI, and wouldn’t be tied to the trigger/printer/camera module start/stop system. This module would be loaded at startup and unloaded on shutdown. This would allow the Photo Booth to use different widget toolkits: QT, Curses, Cocoa, WinForms, or whatever else. Under this scheme, the current GTK+ interface would be abstracted into the reference UI Module.

DMP Photo Booth: Release Candidate 1

It’s been a long time coming, but the day is almost here: the day DMP Photo Booth is officially released.

Following last week’s successful stress test, I’ve been doing some last-minute touch-up work. I’ve been preparing my laptop for the big day, and finding and squashing some bugs.

DMP Photo Booth RC1 using my fancy new dark GTK theme

DMP Photo Booth RC1 using my fancy new dark GTK theme

Now things are coming along, and I feel the time has come to proceed to RC1. This means that barring any major new show stoppers, DMP Photo Booth will proceed to version 1.0 on June 22.

You can find the latest release here. On that page you’ll find the latest source for DMP Photo Booth and the reference modules, as well as a pre-compiled version for Debian/AMD64. Just extract the tarball into a folder and double-click the executable and you’re off! It comes pre-configured with sane defaults.

Moving forward, I plan to work on a “GTK Trigger Module”. This will just show a window with a button you can click to trigger the photo session. I understand that not everybody feels like constructing an Arduino thingamabober, and that this is surely the only thing preventing DMP Photo Booth from going viral on a global scale. Hopefully this is done by 1.0, but if not it will likely make it into a version 1.0.1, to be released shortly after 1.0.

DMP Photo Booth: To The Test

It’s been a long year leading up to this, but last week DMP Photo Booth saw its first time out in the wild.

Last weekend my fiancée had her bachelorette party. Since it was No Boys Allowed, I wouldn’t be able to babysit the Photo Booth. Luckily for me the event went off largely without issue.

IMG_3212

I spent the week leading up to the event writing documentation. Channeling my past life as an IT professional, I wrote up an HTML page documenting the use of the Photo Booth and some common issues. This documentation will probably get uploaded to either this site or github soon. I need to strip out some stuff specifically relating to my computer first.

After that and a quick walkthrough the night before, it was go time. As the appointed hour arrived, I watched my phone for calls. The good news is that none came. The Photo Booth performed as advertised, with only a few minor difficulties caused by my computer. The only issue with the actual Photo Booth itself that was reported to me is that there is a slight delay between a picture being taken and the trigger counting down. An issue has been opened against this in Github.

The final stretch is here now. The wedding is on the 21st, and the Photo Booth must be complete by then. Honestly, if the day were tomorrow I’d be confident the Photo Booth would work. However, there is always room for polish. There remains bugs to be squashed, documentation to be finalized, and packaging to be done.

DMP Photo Booth: Crunch Time

Over the last few months, I’ve become distracted. As anybody who’s ever committed to one project can probably tell you: it stops being exciting. What was once your pride and joy becomes the daily grind. Things get stale. As was the case with me, I suspect that this happens for most people when development of new features ends and the focus shifts to bug fixes.

I became distracted. My mind began to wander to the next thing, which in my case ended up being Haskell. I began learning Haskell, and it was definitely educational. I learned a lot with Haskell, and I plan to stick with it so that when I list it on my resume, I don’t get destroyed on a whiteboard test. Then came The Great Matrix Affair of 2014; I got overwhelmed at school. I spent so much time studying and doing homework that I couldn’t muster up the motivation to program. Things fell by the wayside, as you can see in my blog post output for February. Luckily for me, that is done, and I have the next two months free to program!

What Remains To Be Done?

It’s been a good 6 – 8 weeks since I’ve really focused on DMP Photo Booth, so the first order of business is the figure out what needs to get done. After doing some brainstorming I’ve settled on a list:

Finish The Trigger

I’ve mostly completed the trigger, but it doesn’t work. The button is soldered wrong, and while it was magically working for a while, it has since stopped. I need to fix the wiring issue, and then drill a hole in the box to put it through. After that and maybe a quick coat of paint it will be complete.

This particular task is due by Friday. I have a series of VIP demos coming up, the first of which is Saturday morning. A few of my cousins are coming in from out of town on Saturday to do wedding stuff, and I want to show it off then. While my cousin Allen is an engineer, and can appreciate a breadboard mockup of what will Totally Become A Real Thing, it certainly won’t be impressive. My cousin Laraine will likely be less amused, but I’m sure I’ll get a pat on the head for my “hard work”. Due to this, it’s important that the trigger be done before then.

Facebook Printer Module

The reference suite of modules was planned to be: a Trigger Module using my Arduino implementation, a Printer Module using CUPS, a Camera Module using LibGPhoto2, and a Lua module for each so that modules can be created using Lua. Of these, only the Lua Printer Module remains to be done. Since creating a Lua module is a trivial task (and not terribly important to be honest), this is a very low priority item.

However, the current Printer Module requires a physical printer. This might not always be ideal, since printers are big and heavy. What if you just want to bring a laptop and a camera and have a photo booth? My fiancée is having just this sort of situation; she wants to use the photo booth at her bachelorette party, but who wants to lug a huge printer to a hotel room? To solve this, I’ve promised her a Facebook Printer Module.

The idea is that when dmp_pm_print() is called, the photo strip will be uploaded to facebook. While I know this sort of thing can be done, I haven’t really researched it much. If it turns out that you have to pay facebook money to get this sort of access, I will find a hosting service that is free. Maybe Photobucket, or Dropbox, or whatever. The important thing is that the photo strips will end up in some central location on the internet so that anybody at the party can download the strip later. Ideally, this central location would be a facebook gallery so people can tag themselvs and be all Web 2.0.

My fiancée’s bachelorette party is in May, so this project isn’t a burning priority. However, this represents the most substantial addition of new functionality remaining to be done, so I plan to work it sooner rather than later. Code will be posted on my Github as it evolves, and like DMP Photo Booth will be available under the GPLv3.

Mac Support

To this point, all my development has been done in Linux. First using Ubuntu, and now using Debian. However, most people don’t use Linux. While Linux is the main target platform for DMP Photo Booth, I have been coding as portably as possible, so it should be little effort to port the application to Mac. Over the next few months, I’ll be making sure it compiles and runs correctly my old Macbook. My Macbook is vintage 2010, as such it is only running Snow Leopard. Therefore if anybody in the audience is a Mac user, and has a current version of OSX, feel free to give it a shot as well and let me know how it goes.

Ideally, my fiancée will bringing the Macbook to her bachelorette party and not my development laptop, therefore this project is due at the same time as the Facebook Printer Module, in May.

Bugs!

Finally, bugs. I need to identify them. I need to squash them. And I need unit tests.

After making a big show about being a good person and doing unit tests, I promptly lost the faith. Soon after implementing those first tests, I made a major change to how I handled errors in my code. Suddenly, all my tests were broken, and I was faced with the choice: rewrite them all, or delete them. After some thought I decided that my tests weren’t that great and that I’d probably change something again and break them all again. So I deleted them.

I’ve got to say, I miss those tests. There has been more than a few times where I’d refactored something and wasn’t sure if it still worked. Sure, it seems to work, but does it really? If I had unit tests in place, I could say with a greater degree of certainty that they do. Plus, “it sounds like a lot of work” is not a good reason not to do something, so it won’t be one for me.

On top of that, I’ll be identifying and squashing bugs the old fashioned way: by trying stuff. I’ve already found a few doozies, and I’m sure I’ll find more. As I find them I’m going to post them on the bug tracker for DMP Photo Booth on Github. I do this for a few reasons: 1) it will provide a public centralized repository of open issues so that I don’t lose or forget about them. 2) I would like others to post bugs here. If I post them here and show that I am fixing them, I feel it will establish confidence that it is looked at and acted upon.

This is due when DMP Photo Booth goes to version 1.0. That is planned to be on June 21, the day of my wedding. DMP Photo Booth will get a good solid night of work as the 80 or so people attending put it through its paces. Assuming all goes to plan with minimal issues, DMP Photo Booth will be declared to be out of Beta. That said, to be truly version 1.0, unit tests must be in place and “all bugs must be fixed”.

Packaging

Currently, DMP Photo Booth is available in source form only. No end-user ever had to compile Microsoft Office; I don’t feel they should have to compile DMP Photo Booth.

To that end, binary distributions will be available for Linux and Mac when DMP Photo Booth goes to version 1.0.

Got My Work Cut Out For Me

It’s a long list to be sure, but I have 4 months to focus on it. However, I’ve decided that I should spend some time focusing on other things too, so that I don’t burn out. To that end, I plan to spend 1 day per week focusing on learning new technologies, and 1 day per week keeping my old skills sharp.

For new technologies, this means things like learning more Haskell, and other languages or frameworks. Whatever strikes my fancy. For old skills this means practicing with Lua and Java, and maybe even C++ if I’m feeling particularly masochistic that day. This will likely take the form of blog posts on topics relating to these, so stay tuned!

The Smallest Things…

For the last few weeks I’ve been banging my head against a problem. I need my Photo Booth application to actually take a photo. It seems like such a simple thing, but it has actually been one of the most difficult ones I’ve encountered. Like the Great PostScript Debacle and the Mystery of the GAsyncQueue Ref before it, I spent a good week banging my head against the wall. I even took a day off to write an entire Lua Camera Module just so I could shell out and call a command line utility to try to work around it.

The best part? If you’ve been following the blog, you know I’m kind of a crybaby about poor documentation. While libgphoto2 is certainly a repeat offender on this count, no amount of documentation could have prepared me for what was to come.

But first, let’s go over my now-working implementation.

Taking A Picture With Libgphoto2

To take a picture, we need 3 functions:

  • gint dmp_cm_camera_init()
  • gint dmp_cm_camera_finalize()
  • gint dmp_cm_camera_capture(gchar * location)

dmp_cm_camera_init

gint dmp_cm_camera_init() { context = gp_context_new(); gp_log_add_func(GP_LOG_ERROR, (GPLogFunc) dmp_cm_log_func, NULL); if (gp_camera_new(&camera) != GP_OK) { //error handling } if (gp_camera_init(camera, context) != GP_OK) { //error handling } return DMP_PB_SUCCESS; }

There are two main structs: Camera and GPContext. A Camera represents, shockingly, a camera attached to the system. A GPContext represents work to be done. Callback functions, data, and other things of that nature.

First we create a new context. Next we can add a log function to accept log messages from libgphoto2. In my experience, no matter what you do you will get a lot of useless garbage output from libgphoto2. For this reason, I recommend you don’t just let this spew to the console or some other user-facing output. At first, I was going to send this to the console queue, but I’ve since decided against using this feature. It is good to know about though in case you need it for troubleshooting.

After all of that is done, we need to create our camera object, and initialize libgphoto2.

dmp_cm_camera_finalize

gint dmp_cm_camera_finalize() { gp_camera_unref(camera); gp_context_unref(context); return DMP_PB_SUCCESS; }

Nothing particularly tricky there. We need to ensure we free our memory when we’re done, so we unref our camera and context. Having seen these two functions, you may be wondering to yourself: “Are we dealing with GObjects here?” Luckily for us, there is a simple test for this:

g_assert(G_IS_OBJECT(camera));

I’ll spare you the effort of running this test: the assertion fails. Too bad really, but it is what it is. Libgphoto2 just uses function names similar to GObject.

dmp_cm_camera_capture

gint dmp_cm_camera_capture(gchar * location) { CameraFile * file; CameraFilePath camera_file_path; gint fd; CameraEventType event_type; void * event_data; if (gp_camera_capture(camera, GP_CAPTURE_IMAGE, &camera_file_path, context) != GP_OK) { //error handling } if ((fd = g_open(location, O_CREAT | O_WRONLY, 0644)) == -1) { //error handling } do { gp_camera_wait_for_event(camera, 1000, &event_type, &event_data, context); if (event_type == GP_EVENT_CAPTURE_COMPLETE) break; } while(event_type != GP_EVENT_TIMEOUT); if (gp_file_new_from_fd(&file, fd) != GP_OK) { //error handling } do { gp_camera_wait_for_event(camera, 1000, &event_type, &event_data, context); } while(event_type != GP_EVENT_TIMEOUT); if (gp_camera_file_get(camera, camera_file_path.folder, camera_file_path.name, GP_FILE_TYPE_NORMAL, file, context) != GP_OK) { //error handling } if (gp_camera_file_delete(camera, camera_file_path.folder, camera_file_path.name, context) != GP_OK) { //error handling } gp_file_free(file); do { gp_camera_wait_for_event(camera, 1000, &event_type, &event_data, context); } while(event_type != GP_EVENT_TIMEOUT); return DMP_PB_SUCCESS; }

This function is where the meat of the process is. First we need to do some housekeeping. We create a CameraFile pointer to represent the actual image file, and a CameraFilePath struct to represent the path to the file. We also create an int for use as a file descriptor, a CameraEventType and void pointer for our calls to gp_cmaera_wait_for_event

Next we call gp_camera_capture which triggers the camera to take a picture. After that is done, we’ll open a file descriptor to save the image. You’ll notice that the call to g_open is enclosed in parentheses. THIS STEP IS 100% MANDATORY Don’t omit it, you’ll be sorry. More on this in a bit.

Next, we wait for the camera to finish working. The camera uses an event system; it will emit events when things happen. After releasing the shutter, the camera has other work to do before it is “done taking the picture”. If you try to do the next step before the camera is ready libgphoto2 will spew garbage to your STDOUT and you’ll have to ctrl+c to fix it. To avoid this, we call gp_camera_wait_for_event while event_type != GP_EVENT_TIMEOUT || GP_EVENT_CAPTURE_COMPLETE Capture complete is obviously the event we care about, but it may have happened while we weren’t listening for it. In that case, we’ll settle for a timeout.

Next up is instantiating our CameraFile. We use our File descriptor that we just opened to call gp_file_new_from_fd. Unfortunately there is no gp_file_new_from_file_pointer which means that this call is POSIX only, and there’s no portable substitute.

After creating our CameraFile we download the image we just took by calling gp_camera_file_get and then delete the file from the camera using gp_camera_file_delete

Finally we make sure no events are pending, then return.

Why Are You Yelling At Me?

Good question. The block in question of course is

if ((fd = g_open(location, O_CREAT | O_WRONLY, 0644)) == -1) { //error handling }

Inside of that if block, I’m assigning a value and testing the result inside of the if statement. This operation is about a 2 out of 10 on the cleverness scale. Normally, you could omit the parentheses around (fd = g_open(location, O_CREAT | O_WRONLY, 0644). However, if we do it here, things go off the rails. Not right away, of course, but a few function calls later we get to:

if (gp_camera_file_get(camera, camera_file_path.folder, camera_file_path.name, GP_FILE_TYPE_NORMAL, file, context) != GP_OK) { //error handling }

As soon as gp_camera_file_get(...) is evaluated, this is spewed to the console:

mystic_runes

…and you have no choice but to kill the process.

Why does this happen? I have no idea. Why does enclosing the call to g_open in parenthesis fix it? Again, no idea. And it only happens here too. I just tried to modify the examples that come with libgphoto2 to reproduce the error and get that screenshot for this post, but it works fine there. Knowing my luck, if you download and build the program, it’ll work fine for you.

As long as it works, I guess…

DMP Camera Module: Shooting For The Moon

So there I was; several hours into my work on the Camera module. I may have mentioned this before, but lack of documentation is a pet peeve of mine. Unfortunately, some times it can’t be avoided. Take libgphoto2. If you click that link, you’ll get taken to a doxygen website. Seems promising, right? Go ahead and poke around, things start to look less rosy as you do. Unfortunately, this seems to be the gold standard of PTP libraries for Linux, so there’s really nothing for it. Right?

Maybe Not

After hours of frustration, I decided to try something crazy. I opened up a command prompt and entered:

gphoto2 --capture-image-and-download

And you know what? My camera took a picture and downloaded it to the current directory. Maybe that’s the answer I’m looking for. DMP Photo Booth doesn’t need to do anything fancy. It just needs to take a picture.

Now, I had been planning to provide modules that call out into Lua to allow people to implement modules in Lua. However, this was always a back-burner project. The sort of thing that happens after version 1.0 is released. But with implementing a libgphoto2 Camera Module seeming like So Much Work, maybe it was time to get on it. At least, for the Camera Module.

dmp_pb_lua_camera_module

So I committed and pushed my work on the Camera Module. I made a copy of it, and removed all the logic. After that, I committed it to the repository. It was officially official.

The first order of business was creating the lua script loader. I needed an init, finalize, and is_initialized function for lua, and a capture function. Let’s take a look:

(I’ve omitted error handling from these examples. If I didn’t they’d be 3 times as long and nobody wants to read that)

gint dmp_cm_lua_initialize() { dmp_cm_state = luaL_newstate(); luaL_openlibs(dmp_cm_state); luaL_loadfile(dmp_cm_state, DMP_CM_MODULE_SCRIPT); lua_pcall(dmp_cm_state, 0, 1, 0); lua_setglobal(dmp_cm_state, DMP_CM_NAMESPACE); lua_getglobal(dmp_cm_state, DMP_CM_NAMESPACE); lua_getfield(dmp_cm_state, -1, DMP_CM_MODULE); lua_pushcfunction(dmp_cm_state, dmp_cm_lua_console_write); lua_setfield(dmp_cm_state, -2, "console_write"); lua_getglobal(dmp_cm_state, DMP_CM_NAMESPACE); lua_getfield(dmp_cm_state, -1, DMP_CM_MODULE); lua_getfield(dmp_cm_state, -1, "initialize"); lua_pcall(dmp_cm_state, 0, 0, 0); is_initialized = TRUE; return DMP_PB_SUCCESS; }

First up is the initialize function. First, I initialize Lua and open the standard library. The call to luaL_loadfile loads the script and pops it onto the stack as a function, which is called by the subsequent call to lua_pcall.

If you’ve been following the blog, you may have noticed that I’m a fan of namespaces. I follow the GLib namespace style and use [NAMESPACE]::[APPLICATION/MODULE]::. I’ve decided that DMP Photo Booth modules implemented in Lua should do this as well. Lua doesn’t have actual namespaces as a language feature, but like most things, they can be approximated using tables. To that end a Lua camera module script should return a table named dmp, which contains a table named cm. In a future version, these will likely be configurable. The module will return the dmp dmp, which is set as a global in the next call.

Next, we must register the console write callback. This is accomplished by getting the dmp.cm table, pushing the console write function, and setting it as a field in dmp.cm.

Next, we get dmp.cm.initialize, and call it.

gint dmp_cm_lua_capture(gchar * location) { lua_getglobal(dmp_cm_state, DMP_CM_NAMESPACE); lua_getfield(dmp_cm_state, -1, DMP_CM_MODULE); lua_getfield(dmp_cm_state, -1, "capture"); lua_pushstring(dmp_cm_state, location); lua_pcall(dmp_cm_state, 1, 0, 0); return DMP_PB_SUCCESS; }

This is the basic method to call a function. First, get the dmp table, then get its cm field. Next, get the function from dmp.cm. After the function is on the stack, we push its arguments onto the stack, and finally we call it. The functions for finalize and is_initialized look strikingly similar, so I’ll spare you.

The Script

The script is extremely simple, thanks to Lua. I can print the whole thing here without editing it, it’s so small:

local dmp = {} dmp.cm = {} function dmp.cm.capture(location) os.execute("gphoto2 --capture-image-and-download" .. "--filename=" .. location) end function dmp.cm.initialize() end function dmp.cm.finalize() end function dmp.cm.is_initialized() return true end return dmp

In the first two lines, we create our dmp.cm namespace tables. Next we define our functions: capture, initialize, finalize, and is_initialized.

Finally, we return our namespace table for use within C. Of the four functions, only capture isn’t a placeholder. In capture, we fork and execute gphoto2, signaling our camera to capture.

How’s That Working Out For Me

Unfortunately, not so great. Well, the Lua module works perfectly. It loads, all functions call without a hitch. And a Lua script is a lot easier to implement than a C module. If only gphoto2 wasn’t so incredibly brittle.

The problem with a command line utility is that you have to count on it to work. Unfortunately, so many things can go wrong with gphoto2. So many errors, so many ways to get into an inconsistent state. Plus, my favorite part about all of this, is that all of this happens by magic! You can do the same thing twice and get different results! Take that Einstein!

No, it seems that my little forray into Lua has come to an end. The Module is live. However, work must re-start on dmp_pb_camera_module. Such a shame…

Bringing The Portability With GModule

As I’ve been writing DMP Photo Booth, I’ve been taking great pains to improve portability. I’ve got a fancy module-based architecture designed to segregate the non-portable sections of the project from the Core. The only problem? A bunch of ugly POSIX calls: dlopen(), dlsym(), and dlclose(). Kind of defeats the purpose of using modules for portability if I don’t load said modules in a portable way, doesn’t it? I thought so too…

Enter GModule

GModule is part of the GLib family of libraries. GModule provides a portable way to handle working with shared libraries. It works on any POSIX compliant platform, as well as Windows, and HP-UX via its shl_load() mechanism. You can read more about GModule in the GLib Reference Manual. While I’m sure there is some edge case that GLib doesn’t cover, this is far more portable than I’d initially envisioned DMP Photo Booth being. (Yay, HP-UX support!)

Another consideration in all of this is the adding of dependencies. However, since I’m already using GTK3 for my GUI, I already have a GLib dependency, so there is no added burden to using GModule.

The How

GModule is actually quite similar to using POSIX dlfcn.h functions. Some semantics are different, but GModule has functions that are roughly equivalent to the POSIX functions.

GModule * g_module_open(const gchar *file_name, GModuleFlags flags);

G_module_open() is the replacement for dlopen() in POSIX. The GModule pointer that it returns is the replacement for the void pointer returned by dlopen(). GModuleFlags is an integer flag that can be boolean or’d in. Your options for this are G_MODULE_BIND_LAZY and G_MODULE_BIND_LOCAL which are equivalent to RTLD_LAZY and RTLD_LOCAL.

gboolean g_module_symbol(GModule *module, const gchar *symbol_name, gpointer *symbol);

This is your replacement for dlsym(), and functions mostly in the same way. module is the gmodule pointer to extract symbols from, symbol_name is the symbol to get, and symbol is the function pointer to populate. This function returns true if successful, and false if not. This function is commonly called like this:

if (!g_module_symbol(dmp_pb_camera_module, "dmp_cm_capture", (gpointer *) &dmp_cm_capture)) { /* error handling here */ }

This idiom can be found throughout the GLib documentation. Did you see the craziness that is argument number 3? Dmp_cm_capture is a function pointer, as you may remember, but GObject tends to make things a little tricky, and will throw thousands of warnings if you don’t cast your function pointer to a gpointer *. The definition of gpointer is:

typedef void* gpointer;

That means that a gpointer * is actually void **. Therefore, you are expected to pass in the address of your pointer using an ampersand, hence (gpointer *) &dmp_cm_capture.

gboolean g_module_close(GModule *module);

As a nice change of pace from the last function, this one is quite straight forward. You pass in your GModule pointer, and it closes it, just like dlclose(), then returns true (or false, if an error occurs). Nothing particularly noteworthy here.

gboolean g_module_supported();

While this function does not line up with a POSIX function, I felt it was important to mention this one. This function returns true if you are on a platform that GModule supports. If you’re on Linux/UNIX/OSX, or Windows, or HP-UX, this should return true. If you’re hacking your Atari-2600, it will most likely return false. Stick this in front of calls to GModule functions and save yourself a headache.

Moving Forward

My design philosophy for DMP Photo Booth is that the Core should compile on any (typical) platform with no changes. Using GLib, this seems to be within reach. With GModules, GTK3 User Interfaces, I’ve kept the faith so far. Looking through the GLib documentation, it has GThreads, so when I inevitably get mired in threaded programming, I should be golden. GLib also has support for Pipes and file IO via GIOChannel, but the documentation claims only partial support in Windows.

Here’s hoping all goes well!

%d bloggers like this: