#include "gtkev.h"
static void gtk_ev_class_init (GtkEvClass *klass);
static void gtk_ev_init (GtkEv *ev);
/* GtkObject functions */
static void gtk_ev_destroy (GtkObject *object);
/* GtkWidget functions */
static gint gtk_ev_event (GtkWidget *widget,
GdkEvent *event);
static void gtk_ev_realize (GtkWidget *widget);
static void gtk_ev_unrealize (GtkWidget *widget);
static void gtk_ev_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_ev_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_ev_draw (GtkWidget *widget,
GdkRectangle *area);
static void gtk_ev_draw_focus (GtkWidget *widget);
static gint gtk_ev_expose (GtkWidget *widget,
GdkEventExpose *event);
static gint gtk_ev_focus_in (GtkWidget *widget,
GdkEventFocus *event);
static gint gtk_ev_focus_out (GtkWidget *widget,
GdkEventFocus *event);
/* GtkEv-specific functions */
static void gtk_ev_paint (GtkEv *ev,
GdkRectangle *area);
static void gtk_ev_paint_event_window (GtkEv *ev,
GdkRectangle *area);
static void gtk_ev_push_text (GtkEv *ev,
const gchar* text);
/* Utility Functions */
static gchar* event_to_text (GdkEvent* event);
static GtkWidgetClass *parent_class = NULL;
guint
gtk_ev_get_type (void)
{
static guint ev_type = 0;
if (!ev_type)
{
static const GtkTypeInfo ev_info =
{
"GtkEv",
sizeof (GtkEv),
sizeof (GtkEvClass),
(GtkClassInitFunc) gtk_ev_class_init,
(GtkObjectInitFunc) gtk_ev_init,
/* reserved_1 */ NULL,
/* reserved_2 */ NULL,
(GtkClassInitFunc) NULL,
};
ev_type = gtk_type_unique (gtk_widget_get_type (), &ev_info);
}
return ev_type;
}
static void
gtk_ev_class_init (GtkEvClass *klass)
{
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
object_class = (GtkObjectClass*) klass;
widget_class = (GtkWidgetClass*) klass;
parent_class = gtk_type_class (gtk_widget_get_type ());
object_class->destroy = gtk_ev_destroy;
widget_class->realize = gtk_ev_realize;
widget_class->unrealize = gtk_ev_unrealize;
widget_class->size_request = gtk_ev_size_request;
widget_class->size_allocate = gtk_ev_size_allocate;
widget_class->draw = gtk_ev_draw;
widget_class->event = gtk_ev_event;
widget_class->draw_focus = gtk_ev_draw_focus;
widget_class->expose_event = gtk_ev_expose;
widget_class->focus_in_event = gtk_ev_focus_in;
widget_class->focus_out_event = gtk_ev_focus_out;
}
static void
gtk_ev_init (GtkEv *ev)
{
GTK_WIDGET_SET_FLAGS (GTK_WIDGET(ev), GTK_CAN_FOCUS);
ev->event_window = NULL;
ev->buffer = NULL;
ev->buffer_end = NULL;
ev->buffer_size = 0;
ev->event_window_rect.x = ev->event_window_rect.y = 0;
ev->event_window_rect.width = ev->event_window_rect.height = 0;
ev->description_rect.x = ev->description_rect.y = 0;
ev->description_rect.width = ev->description_rect.height = 0;
}
GtkWidget*
gtk_ev_new (void)
{
GtkEv *ev;
ev = gtk_type_new (gtk_ev_get_type ());
return GTK_WIDGET (ev);
}
/* GtkObject functions */
static void
gtk_ev_destroy (GtkObject *object)
{
GtkEv* ev;
GList* tmp;
g_return_if_fail(object != NULL);
g_return_if_fail(GTK_IS_EV(object));
ev = GTK_EV(object);
tmp = ev->buffer;
while (tmp != NULL)
{
g_strfreev((gchar**)tmp->data);
tmp = g_list_next(tmp);
}
g_list_free(ev->buffer);
ev->buffer = NULL;
ev->buffer_end = NULL;
ev->buffer_size = 0;
/* Chain up */
if (GTK_OBJECT_CLASS(parent_class)->destroy)
(* GTK_OBJECT_CLASS(parent_class)->destroy) (object);
}
/* GtkWidget functions */
static gint
gtk_ev_event (GtkWidget *widget,
GdkEvent *event)
{
GtkEv* ev;
g_return_val_if_fail(widget != NULL, FALSE);
g_return_val_if_fail(GTK_IS_EV(widget), FALSE);
ev = GTK_EV(widget);
if (event->any.window == widget->window)
{
if (GTK_WIDGET_CLASS(parent_class)->event)
return (* GTK_WIDGET_CLASS(parent_class)->event) (widget, event);
else
return FALSE;
}
else
{
gchar* text;
/* The event is either on ev->event_window, or it is a key event
* passed down to us from the toplevel GtkWindow
*/
text = event_to_text(event);
gtk_ev_push_text(ev, text);
g_free(text);
/* If it was a motion event, make sure we get more */
if (event->type == GDK_MOTION_NOTIFY)
{
gdk_window_get_pointer(ev->event_window, NULL, NULL, NULL);
}
/* We didn't "handle" the event, just listened in on it. */
return FALSE;
}
}
static void
gtk_ev_realize (GtkWidget *widget)
{
GdkWindowAttr attributes;
gint attributes_mask;
GtkEv* ev;
GdkCursor* cursor;
g_return_if_fail(widget != NULL);
g_return_if_fail(GTK_IS_EV(widget));
ev = GTK_EV(widget);
/* Set realized flag */
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
/* Main widget window */
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = widget->allocation.x;
attributes.y = widget->allocation.y;
attributes.width = widget->allocation.width;
attributes.height = widget->allocation.height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.visual = gtk_widget_get_visual (widget);
attributes.colormap = gtk_widget_get_colormap (widget);
attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
&attributes, attributes_mask);
gdk_window_set_user_data (widget->window, widget);
/* Event window */
cursor = gdk_cursor_new(GDK_CROSSHAIR);
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = ev->event_window_rect.x;
attributes.y = ev->event_window_rect.y;
attributes.width = ev->event_window_rect.width;
attributes.height = ev->event_window_rect.height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.visual = gtk_widget_get_visual (widget);
attributes.colormap = gtk_widget_get_colormap (widget);
attributes.event_mask = GDK_ALL_EVENTS_MASK;
attributes.cursor = cursor;
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL |
GDK_WA_COLORMAP | GDK_WA_CURSOR;
ev->event_window = gdk_window_new (widget->window,
&attributes, attributes_mask);
gdk_window_set_user_data (ev->event_window, widget);
gdk_window_show(ev->event_window);
gdk_cursor_destroy(cursor);
/* Style */
widget->style = gtk_style_attach (widget->style, widget->window);
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
gdk_window_set_background (ev->event_window,
&widget->style->base[GTK_STATE_NORMAL]);
}
static void
gtk_ev_unrealize (GtkWidget *widget)
{
GtkEv* ev;
g_return_if_fail(widget != NULL);
g_return_if_fail(GTK_IS_EV(widget));
ev = GTK_EV(widget);
/* Hide all windows */
if (GTK_WIDGET_MAPPED (widget))
gtk_widget_unmap (widget);
GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
/* Destroy our child window */
if (ev->event_window)
{
gdk_window_set_user_data(ev->event_window, NULL);
gdk_window_destroy(ev->event_window);
ev->event_window = NULL;
}
/* This destroys widget->window and unsets the realized flag
*/
if (GTK_WIDGET_CLASS(parent_class)->unrealize)
(* GTK_WIDGET_CLASS(parent_class)->unrealize) (widget);
}
static void
gtk_ev_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
g_return_if_fail(widget != NULL);
g_return_if_fail(GTK_IS_EV(widget));
/*
* GtkEv always wants to be the same fixed size.
*/
requisition->width = 450;
requisition->height = 300;
}
static void
gtk_ev_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
static const gint spacing = 10;
GtkEv* ev;
g_return_if_fail(widget != NULL);
g_return_if_fail(GTK_IS_EV(widget));
ev = GTK_EV(widget);
widget->allocation = *allocation;
ev->event_window_rect.width =
MAX(allocation->width - spacing*2, 0);
ev->event_window_rect.height =
MAX(allocation->height / 5 - spacing / 2, 0);
ev->event_window_rect.x =
(allocation->width - ev->event_window_rect.width)/2;
ev->event_window_rect.y =
MIN(spacing, allocation->height);
ev->description_rect.x = ev->event_window_rect.x;
ev->description_rect.y =
ev->event_window_rect.y + ev->event_window_rect.height + spacing;
ev->description_rect.width =
ev->event_window_rect.width;
ev->description_rect.height =
MAX((allocation->height - ev->event_window_rect.height - spacing*3), 0);
if (GTK_WIDGET_REALIZED (widget))
{
gdk_window_move_resize (widget->window,
allocation->x,
allocation->y,
allocation->width,
allocation->height);
gdk_window_move_resize (ev->event_window,
ev->event_window_rect.x,
ev->event_window_rect.y,
ev->event_window_rect.width,
ev->event_window_rect.height);
}
}
static void
gtk_ev_draw (GtkWidget *widget,
GdkRectangle *area)
{
GdkRectangle event_window_area;
GdkRectangle intersection;
GtkEv* ev;
g_return_if_fail(widget != NULL);
g_return_if_fail(GTK_IS_EV(widget));
ev = GTK_EV(widget);
gtk_ev_paint(ev, area);
event_window_area = *area;
if (gdk_rectangle_intersect(area, &ev->event_window_rect, &intersection))
{
/* Make the intersection relative to the event window */
intersection.x -= ev->event_window_rect.x;
intersection.y -= ev->event_window_rect.y;
gtk_ev_paint_event_window(ev, &intersection);
}
}
static void
gtk_ev_draw_focus (GtkWidget *widget)
{
GdkRectangle rect;
GtkEv* ev;
g_return_if_fail(widget != NULL);
g_return_if_fail(GTK_IS_EV(widget));
ev = GTK_EV(widget);
rect.x = 0;
rect.y = 0;
rect.width = widget->allocation.width;
rect.height = widget->allocation.height;
if (GTK_WIDGET_DRAWABLE (ev))
gtk_ev_paint(ev, &rect);
}
static gint
gtk_ev_expose (GtkWidget *widget,
GdkEventExpose *event)
{
if (event->window == widget->window)
gtk_ev_paint(GTK_EV(widget), &event->area);
else if (event->window == GTK_EV(widget)->event_window)
gtk_ev_paint_event_window(GTK_EV(widget), &event->area);
else
g_assert_not_reached();
return TRUE;
}
static gint
gtk_ev_focus_in (GtkWidget *widget,
GdkEventFocus *event)
{
g_return_val_if_fail(widget != NULL, FALSE);
g_return_val_if_fail(GTK_IS_EV(widget), FALSE);
GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
gtk_widget_draw_focus (widget);
return FALSE;
}
static gint
gtk_ev_focus_out (GtkWidget *widget,
GdkEventFocus *event)
{
g_return_val_if_fail(widget != NULL, FALSE);
g_return_val_if_fail(GTK_IS_EV(widget), FALSE);
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
gtk_widget_draw_focus (widget);
return FALSE;
}
/* GtkEv-specific functions */
static void
gtk_ev_paint (GtkEv *ev,
GdkRectangle *area)
{
GtkWidget* widget;
g_return_if_fail(ev != NULL);
g_return_if_fail(GTK_IS_EV(ev));
widget = GTK_WIDGET(ev);
if (!GTK_WIDGET_DRAWABLE (widget))
return;
gdk_window_clear_area (widget->window,
area->x,
area->y,
area->width,
area->height);
gdk_gc_set_clip_rectangle(widget->style->black_gc, area);
/* Draw a black rectangle around the event window */
gdk_draw_rectangle(widget->window,
widget->style->black_gc,
FALSE,
ev->event_window_rect.x - 1,
ev->event_window_rect.y - 1,
ev->event_window_rect.width + 2,
ev->event_window_rect.height + 2);
gdk_gc_set_clip_rectangle(widget->style->black_gc, NULL);
/* Draw text in the description area, if applicable */
if (ev->buffer)
{
GdkRectangle intersection;
if (gdk_rectangle_intersect(area,
&ev->description_rect,
&intersection))
{
static const gint space = 2;
gint line;
gint step;
gint first_baseline;
GList* tmp;
step = widget->style->font->ascent +
widget->style->font->descent + space;
first_baseline = ev->description_rect.y +
widget->style->font->ascent + space;
line = 0;
tmp = ev->buffer;
while (tmp != NULL)
{
gchar** this_event = tmp->data;
gint i = 0;
while (this_event[i])
{
gtk_paint_string (widget->style,
widget->window,
widget->state,
&intersection, widget, "ev",
ev->description_rect.x,
first_baseline + line*step,
this_event[i]);
++i;
++line;
}
/* Bail out if we're off the bottom; the "- 2*step" is
* needed because the next baseline may be outside the
* redraw area but we are interested in the whole row of
* text, not the baseline. The 2* is because line is one
* larger than we've actually drawn.
*/
if ((first_baseline + line*step - 2*step) >
(intersection.y + intersection.height))
break;
tmp = g_list_next(tmp);
}
}
}
if (GTK_WIDGET_HAS_FOCUS (widget))
{
gtk_paint_focus (widget->style, widget->window,
area, widget, "ev",
widget->allocation.x, widget->allocation.y,
widget->allocation.width-1, widget->allocation.height-1);
}
}
static void
gtk_ev_paint_event_window (GtkEv *ev,
GdkRectangle *area)
{
GtkWidget* widget;
gint width;
gint x, y;
const char* title;
g_return_if_fail(ev != NULL);
g_return_if_fail(GTK_IS_EV(ev));
widget = GTK_WIDGET(ev);
if (!GTK_WIDGET_DRAWABLE (widget))
return;
title = _("Event Window");
gdk_window_clear_area (ev->event_window,
area->x,
area->y,
area->width,
area->height);
gdk_gc_set_clip_rectangle(widget->style->black_gc, area);
/* Clearly it would be better to cache this */
width = gdk_string_width(widget->style->font,
title);
x = (ev->event_window_rect.width - width)/2;
y = widget->style->font->ascent + 2;
gdk_draw_string(ev->event_window,
widget->style->font,
widget->style->black_gc,
x, y,
title);
gdk_gc_set_clip_rectangle(widget->style->black_gc, NULL);
}
static void
gtk_ev_push_text (GtkEv *ev,
const gchar* text)
{
if (text)
{
gchar** event;
event = g_strsplit(text, "\n", 10);
ev->buffer = g_list_prepend(ev->buffer, event);
ev->buffer_size += 1;
/* See if this was the first one we added */
if (ev->buffer_end == NULL)
{
ev->buffer_end = ev->buffer;
}
/* See if we have too many to possibly fit on-screen */
if (ev->buffer_size > 100)
{
GList* prev = ev->buffer_end->prev;
prev->next = NULL;
g_strfreev(ev->buffer_end->data);
g_list_free_1(ev->buffer_end);
ev->buffer_end = prev;
ev->buffer_size -= 1;
}
}
if (GTK_WIDGET_DRAWABLE (ev))
gtk_widget_queue_draw_area(GTK_WIDGET(ev),
ev->description_rect.x,
ev->description_rect.y,
ev->description_rect.width,
ev->description_rect.height);
}
static gchar*
event_name_line(GdkEvent* event)
{
switch (event->type)
{
case GDK_NOTHING:
return g_strdup(_("Invalid event!\n"));
break;
case GDK_DELETE:
return g_strdup(_("Delete\n"));
break;
case GDK_DESTROY:
return g_strdup(_("Destroy\n"));
break;
case GDK_EXPOSE:
return g_strdup(_("Expose\n"));
break;
case GDK_MOTION_NOTIFY:
return g_strdup(_("Motion Notify\n"));
break;
case GDK_BUTTON_PRESS:
return g_strdup(_("Button Press\n"));
break;
case GDK_2BUTTON_PRESS:
return g_strdup(_("2 Button Press\n"));
break;
case GDK_3BUTTON_PRESS:
return g_strdup(_("3 Button Press\n"));
break;
case GDK_BUTTON_RELEASE:
return g_strdup(_("Button Release\n"));
break;
case GDK_KEY_PRESS:
return g_strdup(_("Key Press\n"));
break;
case GDK_KEY_RELEASE:
return g_strdup(_("Key Release\n"));
break;
case GDK_ENTER_NOTIFY:
return g_strdup(_("Enter Notify\n"));
break;
case GDK_LEAVE_NOTIFY:
return g_strdup(_("Leave Notify\n"));
break;
case GDK_FOCUS_CHANGE:
return g_strdup(_("Focus Change\n"));
break;
case GDK_CONFIGURE:
return g_strdup(_("Configure\n"));
break;
case GDK_MAP:
return g_strdup(_("Map\n"));
break;
case GDK_UNMAP:
return g_strdup(_("Unmap\n"));
break;
case GDK_PROPERTY_NOTIFY:
return g_strdup(_("Property Notify\n"));
break;
case GDK_SELECTION_CLEAR:
return g_strdup(_("Selection Clear\n"));
break;
case GDK_SELECTION_REQUEST:
return g_strdup(_("Selection Request\n"));
break;
case GDK_SELECTION_NOTIFY:
return g_strdup(_("Selection Notify\n"));
break;
case GDK_PROXIMITY_IN:
return g_strdup(_("Proximity In\n"));
break;
case GDK_PROXIMITY_OUT:
return g_strdup(_("Proximity Out\n"));
break;
case GDK_DRAG_ENTER:
return g_strdup(_("Drag Enter\n"));
break;
case GDK_DRAG_LEAVE:
return g_strdup(_("Drag Leave\n"));
break;
case GDK_DRAG_MOTION:
return g_strdup(_("Drag Motion\n"));
break;
case GDK_DRAG_STATUS:
return g_strdup(_("Drag Status\n"));
break;
case GDK_DROP_START:
return g_strdup(_("Drop Start\n"));
break;
case GDK_DROP_FINISHED:
return g_strdup(_("Drop Finished\n"));
break;
case GDK_CLIENT_EVENT:
return g_strdup(_("Client Event\n"));
break;
case GDK_VISIBILITY_NOTIFY:
return g_strdup(_("Visibility Notify\n"));
break;
case GDK_NO_EXPOSE:
return g_strdup(_("No Expose\n"));
break;
default:
g_assert_not_reached();
return NULL;
break;
}
}
static gchar*
any_event_line(GdkEvent* event)
{
guint32 event_time;
event_time = gdk_event_get_time(event);
if (event_time != GDK_CURRENT_TIME)
return g_strdup_printf(_("Window: %p Time: %u send_event: %s\n"),
event->any.window,
event_time,
event->any.send_event ? _("True") : _("False"));
else
return g_strdup_printf(_("Window: %p send_event: %s\n"),
event->any.window,
event->any.send_event ? _("True") : _("False"));
}
#define MAX_STATES 30
static gchar*
event_state_line(GdkModifierType state)
{
gchar** states;
gint n_active;
states = g_new(gchar*, MAX_STATES);
n_active = 0;
if (state & GDK_SHIFT_MASK)
{
states[n_active] = _("Shift");
++n_active;
}
if (state & GDK_LOCK_MASK)
{
states[n_active] = _("Lock");
++n_active;
}
if (state & GDK_CONTROL_MASK)
{
states[n_active] = _("Ctrl");
++n_active;
}
if (state & GDK_MOD1_MASK)
{
states[n_active] = _("Mod1");
++n_active;
}
if (state & GDK_MOD2_MASK)
{
states[n_active] = _("Mod2");
++n_active;
}
if (state & GDK_MOD3_MASK)
{
states[n_active] = _("Mod3");
++n_active;
}
if (state & GDK_MOD4_MASK)
{
states[n_active] = _("Mod4");
++n_active;
}
if (state & GDK_MOD5_MASK)
{
states[n_active] = _("Mod5");
++n_active;
}
if (state & GDK_BUTTON1_MASK)
{
states[n_active] = _("Button1");
++n_active;
}
if (state & GDK_BUTTON2_MASK)
{
states[n_active] = _("Button2");
++n_active;
}
if (state & GDK_BUTTON3_MASK)
{
states[n_active] = _("Button3");
++n_active;
}
if (state & GDK_BUTTON4_MASK)
{
states[n_active] = _("Button4");
++n_active;
}
if (state & GDK_BUTTON5_MASK)
{
states[n_active] = _("Button4");
++n_active;
}
if (state & GDK_RELEASE_MASK)
{
states[n_active] = _("Release");
++n_active;
}
if (n_active == 0)
return NULL;
else
{
/* Not efficient, but not important */
gchar* str = NULL;
gchar* tmp = NULL;
guint i = 0;
while (i < n_active)
{
if (str)
{
tmp = str;
str = g_strconcat(str, " | ", states[i], NULL);
g_free(tmp);
}
else
{
str = g_strdup(states[i]);
}
++i;
}
tmp = str;
str = g_strconcat(str, "\n", NULL);
g_free(tmp);
return str;
}
}
static gchar*
event_to_text (GdkEvent* event)
{
gchar* any_line;
gchar* name_line;
gchar* entire_line;
gchar* detail;
gchar* state;
name_line = event_name_line(event);
any_line = any_event_line(event);
entire_line = NULL;
detail = NULL;
state = NULL;
switch (event->type)
{
case GDK_NOTHING:
break;
case GDK_DELETE:
break;
case GDK_DESTROY:
break;
case GDK_EXPOSE:
detail = g_strdup_printf(_("Area: %d,%d %dx%d Count: %d\n"),
event->expose.area.x,
event->expose.area.y,
event->expose.area.width,
event->expose.area.height,
event->expose.count);
break;
case GDK_MOTION_NOTIFY:
detail = g_strdup_printf(_("x: %g y: %g\n"),
event->motion.x,
event->motion.y);
state = event_state_line(event->motion.state);
break;
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
detail = g_strdup_printf(_("Button: %d\n"),
event->button.button);
state = event_state_line(event->button.state);
break;
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
detail = g_strdup_printf(_("Keyval: GDK_%s Text: %s\n"),
gdk_keyval_name(event->key.keyval),
event->key.string);
state = event_state_line(event->key.state);
break;
case GDK_ENTER_NOTIFY:
break;
case GDK_LEAVE_NOTIFY:
break;
case GDK_FOCUS_CHANGE:
break;
case GDK_CONFIGURE:
break;
case GDK_MAP:
break;
case GDK_UNMAP:
break;
case GDK_PROPERTY_NOTIFY:
break;
case GDK_SELECTION_CLEAR:
break;
case GDK_SELECTION_REQUEST:
break;
case GDK_SELECTION_NOTIFY:
break;
case GDK_PROXIMITY_IN:
break;
case GDK_PROXIMITY_OUT:
break;
case GDK_DRAG_ENTER:
break;
case GDK_DRAG_LEAVE:
break;
case GDK_DRAG_MOTION:
break;
case GDK_DRAG_STATUS:
break;
case GDK_DROP_START:
break;
case GDK_DROP_FINISHED:
break;
case GDK_CLIENT_EVENT:
break;
case GDK_VISIBILITY_NOTIFY:
break;
case GDK_NO_EXPOSE:
break;
default:
g_assert_not_reached();
break;
}
if (entire_line == NULL)
{
/* Assumes we always have a detail if we have a state */
entire_line = g_strconcat(name_line,
" ", any_line,
detail ? " " : NULL, detail,
state ? " " : NULL, state,
NULL);
}
g_free(name_line);
g_free(any_line);
g_free(detail);
g_free(state);
return entire_line;
}
|