I have a working version of this program I was working on. I'm calling it "gaptcache" for now, as it is a gui that runs the debian apt-cache program. It runs the program as a regular user so that you can do things like run aptitude from a separate command line and not have to worry about locking (or that's the idea anyway). It doesn't have a command line input itself. It's still pretty new, so if you see bugs, like memory leaks etc, let me know. I'm brand new to gtk.
I had a lot of help from a GTK+ tutorial and from Tadeboro. It's 331 lines now, all in one file, and of course it's only usefull on debian systems with apt-cache.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
typedef struct _Data Data;
struct _Data
{
GtkEntry *entry;
GtkTreeView *tree;
GtkTextView *text;
};
/* function definitions */
static void
search_click( GtkWidget *widget,
Data *data );
static GtkWidget *
create_list( Data *data );
static GtkWidget *
create_text( Data *data );
static void
insert_description ( Data *data );
/* Function Implementation */
static void search_click( GtkWidget *widget,
Data *data )
{
/* Tree view vars */
GtkListStore *store;
GtkTreeIter tree_iter;
const gchar *entry_text;
/* g_spawn_command_line_sync variables*/
gchar *command_line;
gchar * standard_output;
GError **gerror;
entry_text = gtk_entry_get_text (data->entry);
/* attempt at running apt-cache */
command_line = g_strconcat( "/usr/bin/apt-cache search " , entry_text, NULL);
g_spawn_command_line_sync ( command_line,
&standard_output,
NULL,
NULL,
gerror );
g_free(command_line);
store = GTK_LIST_STORE( gtk_tree_view_get_model( data->tree ) );
gtk_list_store_clear(store);
/* parse standard_output */
gint x = 0;
while ('\0' != standard_output[x] && '\n' != standard_output[x]) {
GString * package;
GString * description;
package = g_string_new("");
description = g_string_new("");
while ( ' ' != standard_output[x] &&
'\0' != standard_output[x])
{
g_string_append_c ( package,
(gchar) standard_output[x]);
x++;
}
/* advance past unused characters */
x = x + 3;
while ( '\n' != standard_output[x] &&
'\0' != standard_output[x] )
{
g_string_append_c (description,
(gchar) standard_output[x]);
x++;
}
x++;
gtk_list_store_append( store, &tree_iter );
gtk_list_store_set( store, &tree_iter,
0, package->str,
1, description->str,
-1 );
g_string_free(package, TRUE);
g_string_free(description, TRUE);
}
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer( data->text );
gtk_text_buffer_set_text( buffer, "Select a package...", -1);
}
/* Create the list of packages */
static GtkWidget *
create_list( Data *data)
{
GtkWidget *scrolled_window;
GtkWidget *tree;
GtkListStore *store;
GtkCellRenderer *cell;
GtkTreeViewColumn *column1, *column2;
GtkTreeSelection *sel;
const gchar *entry_text;
if (data != NULL) {
entry_text = gtk_entry_get_text (data->entry);
}
else {
entry_text = "";
}
/* Create a new scrolled window, with scrollbars only if needed */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
tree = gtk_tree_view_new_with_model ( GTK_TREE_MODEL(store));
g_object_unref(G_OBJECT(store));
gtk_container_add(GTK_CONTAINER( scrolled_window), tree);
cell = gtk_cell_renderer_text_new ();
column1 = gtk_tree_view_column_new_with_attributes ("Packages",
cell,
"text", 0,
NULL);
column2 = gtk_tree_view_column_new_with_attributes ("Description",
cell,
"text", 1,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree),
column1);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree),
column2);
sel = gtk_tree_view_get_selection ( GTK_TREE_VIEW (tree));
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
g_signal_connect_swapped( sel, "changed",
G_CALLBACK(insert_description),
data);
data->tree = GTK_TREE_VIEW(tree);
return (scrolled_window);
}
/* */
static void
insert_description( Data *data )
{
GtkTextBuffer *buffer;
GtkTreeIter selected_row;
GtkTreeModel *model;
gchar *selected;
GtkTreeSelection *sel;
sel = gtk_tree_view_get_selection ( GTK_TREE_VIEW (data->tree));
if( gtk_tree_selection_get_selected(sel, &model, &selected_row) )
{
/* find which selection was pressed */
gtk_tree_model_get ( GTK_TREE_MODEL( model ),
&selected_row,
0,
&selected,
-1);
/* g_spawn_command_line_sync variables*/
gchar *command_line;
gchar * standard_output;
GError **gerror;
/* attempt at running apt-cache */
command_line = g_strconcat( "/usr/bin/apt-cache show " , selected, NULL);
g_spawn_command_line_sync ( command_line,
&standard_output,
NULL,
NULL,
gerror );
g_free(command_line);
g_free(selected);
/* Add this text to text view */
buffer = gtk_text_view_get_buffer( data->text );
gtk_text_buffer_set_text( buffer, standard_output, -1);
g_free(standard_output);
}
}
/* Create a scrolled text area that displays a "package description" */
static GtkWidget *
create_text( Data *data )
{
GtkWidget *text;
GtkWidget *swindow;
/* Text view vars */
GtkTextBuffer *buffer;
GtkTextIter text_iter;
/* Create scrolled window */
swindow = gtk_scrolled_window_new( NULL, NULL );
gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swindow ),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC );
/* Text view */
text = gtk_text_view_new();
gtk_text_view_set_editable ( GTK_TEXT_VIEW (text) , FALSE);
gtk_container_add( GTK_CONTAINER( swindow ), text );
data->text = GTK_TEXT_VIEW( text );
/* Append this text to the text already present in text view */
buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(text) );
gtk_text_buffer_get_iter_at_offset( buffer, &text_iter, -1 );
gtk_text_buffer_insert( buffer, &text_iter,
"Package description will appear here\n"
, -1 );
//data->text = GTK_TEXT_VIEW( text );
return( swindow );
}
/* main */
int main( int argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *vpaned;
GtkWidget *text;
GtkWidget *vbox, *hbox;
GtkWidget *button;
GtkWidget *entry;
GtkWidget *list;
Data data;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Gaptcache");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_window_set_default_size (GTK_WINDOW (window), 550, 400);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
/* create a vpaned widget and add it to window */
vbox = gtk_vbox_new(FALSE, 5);
gtk_container_add (GTK_CONTAINER (window), vbox);
hbox = gtk_hbox_new(FALSE, 5);
gtk_box_pack_start( GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
/* Create Text Entry Widget and callback */
entry = gtk_entry_new();
g_signal_connect( G_OBJECT(entry), "activate",
G_CALLBACK (search_click),
&data);
g_signal_connect_swapped( G_OBJECT(entry), "activate",
G_CALLBACK (insert_description),
&data);
/* Pack Entry Widget into horizontal box */
gtk_box_pack_start( GTK_BOX (hbox), entry, TRUE, TRUE, 0);
/* point data.entry at Entry Widget */
data.entry = GTK_ENTRY(entry);
/* make button and callback */
button = gtk_button_new_from_stock( GTK_STOCK_FIND );
g_signal_connect ( G_OBJECT (button), "clicked",
G_CALLBACK (search_click),
&data );
g_signal_connect_swapped ( G_OBJECT(button), "clicked",
G_CALLBACK (insert_description),
&data);
/* Pack Button Widget into horizontal box */
gtk_box_pack_start( GTK_BOX (hbox), button, TRUE, TRUE, 0);
vpaned = gtk_vpaned_new ();
gtk_paned_set_position( GTK_PANED(vpaned), 125);
gtk_box_pack_start( GTK_BOX (vbox), vpaned, TRUE, TRUE, 0);
gtk_entry_set_text( GTK_ENTRY (entry), "packagename" );
list = create_list(&data);
gtk_paned_add1 (GTK_PANED (vpaned), list );
text = create_text (&data);
gtk_paned_add2 (GTK_PANED (vpaned), text);
gtk_widget_show_all(window);
gtk_main ();
return 0;
}
this is the makefile:
[code=]
CC = gcc
CFLAGS = -Wall \
-DG_DISABLE_DEPRECATED \
-DGDK_DISABLE_DEPRECATED \
-DGDK_PIXBUF_DISABLE_DEPRECATED \
-DGTK_DISABLE_DEPRECATED
gaptcache: gaptcache.c
$(CC) gaptcache.c -o gaptcache $(CFLAGS) `pkg-config gtk+-2.0 --cflags --libs`
clean:
rm -f *.o gaptcache
[/code]