Science Daily: Jupiter
- Heart of Jovian moon's volcanic rage December 13, 2024
- NASA's Hubble celebrates decade of tracking outer planets December 9, 2024
In my quest to build a Linux replacment for DSLRFocus, I’m hitting a steep learning curve with Glade, Gtk, and gPhoto. I’m making progress, but it is slow. I’ve also come to realize that sometimes "best practices" can get in the way. What do I mean?
Well, in the gPhoto library, a Camera object is hidden with the typical C-style opaque typedef. So you can’t see inside it. You’re not supposed to see inside it, that’s private information and you use the accessors. That’s okay for the most part, but sometimes I’d kind of like to be able to see the internals in the debugger simply because the API documentation isn’t always clear. No can do. In a way, that’s a good thing, since I really don’t want to code my application to take advantage of the implementation, but it does mean I have to ask a lot of stupid questions on the development list. And its a low-traffic list so I don’t have a lot of people to ask 🙁
Gtk has its own learning curve. Something as simple as displaying a list of items to let someone choose is not hard. In my case, it was getting gPhoto to detected cameras attached to the computer and put those in a list. You can choose any number to connect to and I keep track. So when you decide you’d like to change which ones are connected, I need to display the changed status.
That’s what a GtkTreeModel is for, something I really didn’t understand. Your model is basically a list of rows, but the row can contain information about the row, not just the data you want to display. So you can insert a column that includes the color information for a row, or whether or not the row should even be displayed. I’ve incorporated my new-found knowledge into my application, but so I don’t lose the original simple example, I’m stuffing it in here.
/*
* Copyright © 2008, Roland Roberts
*
*/
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <glade/glade.h>
/* Global GladeXML struct for use by anyone needing to look up a UI
element. */
GladeXML *xml;
enum _state {IS_UNKNOWN, IS_CONNECTED, IS_NOT_CONNECTED, IS_NEWLY_DETECTED };
typedef enum _state state;
char *_colormap[] = { "red", "#008000", "blue", "black" };
struct _data {
const char *name;
const char *port;
state connected;
};
struct _data data[] =
{ { "RoloCam 2000", "hyper:001,007", IS_CONNECTED },
{ "AstroCam 100", "air:27,31", IS_NOT_CONNECTED },
{ "NoCam 2020", "pipe:/smoke/0", IS_UNKNOWN },
{ "NoCam 2021", "pipe:/smoke/1", IS_UNKNOWN },
{ "RoloCam 2001", "hyper:001,007", IS_NEWLY_DETECTED },
{ "AstroCam 101", "air:27,31", IS_NOT_CONNECTED },
{ "NoCam 3020", "pipe:/smoke/2", IS_UNKNOWN },
{ "NoCam 3021", "pipe:/smoke/3", IS_NEWLY_DETECTED },
{ 0, 0, 0 },
};
enum _model_columns { NAME_COL, PORT_COL, STATE_COL, COLOR_COL, NUM_COLS };
void
main_window_destroy_cb(GtkObject *object, gpointer user_data)
{
gtk_main_quit();
}
void
main_menubar_quit_activate_cb(GtkObject *object, gpointer user_data)
{
gtk_main_quit();
}
int
main(int argc, char *argv[])
{
GtkWidget *window;
GtkTreeView *treeview;
GtkTreeSelection *selection;
GtkCellRenderer *renderer;
GtkListStore *store;
struct _data *row;
int i;
gtk_init(&argc, &argv);
xml = glade_xml_new("dummy.glade", NULL, NULL);
window = GTK_WIDGET(glade_xml_get_widget(xml, "window1"));
glade_xml_signal_autoconnect(xml);
treeview = GTK_TREE_VIEW(glade_xml_get_widget(xml, "treeview1"));
selection = gtk_tree_view_get_selection(treeview);
gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
/* Only need one generic renderer for our list. */
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_insert_column_with_attributes(treeview, -1, "Name", renderer,
"text", NAME_COL, "foreground", COLOR_COL, NULL);
gtk_tree_view_insert_column_with_attributes(treeview, -1, "Port", renderer,
"text", PORT_COL, "foreground", COLOR_COL, NULL);
gtk_tree_view_insert_column_with_attributes(treeview, -1, "State", renderer,
"text", STATE_COL, "foreground", COLOR_COL, NULL);
gtk_tree_view_insert_column_with_attributes(treeview, -1, "Color", renderer,
"text", COLOR_COL, "foreground", COLOR_COL, NULL);
store = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_INT, G_TYPE_STRING);
gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
for (i = 0; data[i].name; i++) {
GtkTreeIter iter;
struct _data *row = &data[i];
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter,
NAME_COL, row->name,
PORT_COL, row->port,
STATE_COL, row->connected,
COLOR_COL, _colormap[row->connected],
-1);
printf("inserted: %-15s %-15s %2d %s\n",
row->name, row->port, row->connected, _colormap[row->connected]);
}
gtk_widget_show(window);
gtk_main ();
return 0;
}
To make this work, you will need to create a "dummy.glade" file which has a top-level window named "window1" and someplace in it a GtkTreeView named "treeview1". Then you should be able to compile like this:
gcc -o dummy `pkg-config --cflags --libs libglade-2.0` -rdynamic dummy.c && ./dummy
assuming you named the application dummy.c.
I owe thanks to Damien Caliste from the gtk-app-devel mailing list for pointing me to an old post of his to get me started on this.
Written by Roland Roberts
Search
.Archives
- October 2024 (1)
- May 2024 (2)
- April 2024 (3)
- September 2022 (5)
- April 2022 (1)
- January 2022 (3)
- December 2021 (4)
- September 2021 (3)
- July 2021 (1)
- January 2021 (1)
- November 2020 (2)
- October 2020 (2)
- September 2020 (2)
- August 2020 (5)
- July 2020 (1)
- November 2019 (2)
- September 2019 (1)
- August 2019 (2)
- September 2017 (1)
- August 2017 (1)
- September 2015 (3)
- August 2015 (2)
- June 2015 (5)
- May 2015 (3)
- May 2013 (2)
- January 2013 (1)
- December 2012 (2)
- September 2012 (1)
- June 2012 (1)
- May 2012 (1)
- October 2011 (2)
- September 2011 (2)
- April 2011 (2)
- March 2011 (10)
- January 2011 (8)
- November 2010 (2)
- October 2010 (1)
- September 2010 (3)
- August 2010 (2)
- July 2010 (1)
- June 2010 (1)
- April 2010 (3)
- February 2010 (3)
- January 2010 (3)
- December 2009 (6)
- November 2009 (3)
- October 2009 (7)
- September 2009 (8)
- August 2009 (4)
- July 2009 (1)
- June 2009 (2)
- May 2009 (2)
- April 2009 (7)
- March 2009 (1)
- February 2009 (6)
- January 2009 (4)
- December 2008 (4)
- November 2008 (3)
- October 2008 (11)
- September 2008 (4)
- August 2008 (5)
- July 2008 (5)
- June 2008 (2)
- April 2008 (4)
- March 2008 (18)
- February 2008 (9)
- November 2007 (1)
- October 2007 (3)
- July 2007 (3)
- April 2007 (1)
- March 2007 (6)
- February 2007 (3)
- December 2006 (3)
- October 2006 (4)
- September 2006 (1)
- July 2006 (5)
- May 2006 (10)
- April 2006 (9)