Re: Help packaging the latest pidgin.

"Neil Munro" <[email protected]>
Newsgroups gmane.comp.autopackage.devel
Message-ID <[email protected]>
Ok here's the latest attempt. I looked at the patch file which shows this:

-    piece = gdk_pixbuf_new_from_file_at_scale (IMAGEDIR "/lb-middle.png",
+    filename = g_build_filename (imagedir, "lb-middle.png", NULL);
+
+    piece = gdk_pixbuf_new_from_file_at_scale (filename,
                            width, height,
                            FALSE,
                            NULL);

I assume this is to make it easier to free the memory at the end of the
function and g_free is run on filename? If it's just about right I shall run
through the finch part of Pidgin see if I can't get the basics of it
autopackaged.

On 01/02/2008, Isak Savo <[email protected]> wrote:
>
> 2008/2/1, Neil Munro <[email protected]>:
> > Ok so I have looked at the lb-window.c for the correct version of the
> > program and have attached what I have done so far. The website shows me
> an
> > example of what I should alter, however I found some things in the code
> I
> > THINK look like they may also need patching, if they don't fine, but
> here's
> > an example of one of the instances:
> >
> >     piece = gdk_pixbuf_new_from_file_at_scale (IMAGEDIR
> > "/lb-middle.png",
> >                            width, height,
> >                            FALSE,
> >                            NULL);
> >
> > The way I am thinking is that it should look like this:
> >
> >     piece = gdk_pixbuf_new_from_file_at_scale(
> > g_build_filename( IMAGEDIR, "lb-middle.png", NULL ),
> >                            width, height,
> >                            FALSE,
> >                            NULL);
> >
>
> Yes and no :)
>
> Yes, it needs changing, but you'r change suggestion is incorrect. You
> see, IMAGEDIR is a string constant, determined at compile time. You
> want to change it to something that is determined at runtime (i.e.
> using binreloc).
>
> So the correct way would be:
>     /* imagedir is of type gchar* and was initialized somewhere else,
> by calling gbr_find_datadir and adding /images/ or somthing to it. */
>     piece = gdk_pixbuf_new_from_file_at_scale( g_build_filename(
> imagedir, "lb-middle.png", NULL ),
>                            width, height,
>                            FALSE,
>                            NULL);
> Also note that you are leaking memory here. g_build_filename expects
> the return value to be free'd by the caller, which you don't do. If
> this code is run several times, it could be a problem.
>
> > I'm not sure though, but I think it's obvious WHY I think it needs
> changing.
> > Also further reading on I have created the glib'd binreloc c and h files
> and
> > moved them into /src in the gnome-launch-box directory, however I'm not
> > entirely sure where to stick them, I downloaded the patch file to see if
> it
> > could be of help, and while it gave me some ideas, I realize if I am to
> > build pidgin, I won't have the liberty of looking at someone else's
> patch so
> > I try not to rely on it.
>
> > Also with regards to the tutorial
> >
> > " Grab binreloc from autopackage CVS, then run the generate.pl script.
> In
> > this instance, we want the glib-ized version not the raw C version so
> pass
> > "glib" as a parameter. It'll output two files: binreloc.c and binreloc.h
> .
> > Add them to Makefile.am and re-run autogen, and now it's integrated with
> our
> > project."
>
> No, apparently they don't have an autogen script. Just run "autoconf"
> (if you change configure.ac) and "automake" if you modifify
> Makefile.am
>
> > There is no autogen.sh file, so I had to fall back upon configure to see
> if
> > it would work, not sure if you wanna change the tutorial to reflect this
> or
> > not. Configure seems to run cleanly though.
>
> See above, you need to call autoconf and/or automake if you change
> Makefile.am and configure.ac.
>
> > What do I do with this code?
> >
> > static gchar *imagedir;
> >
> > /* will be called automatically before main() */
> > static void __attribute__((constructor))
> > locate_image_dir ()
> > {
> >  if (gbr_init (NULL))
> >
> >  imagedir = g_build_filename (gbr_find_data_dir (DATADIR), "lb",
> "images",
> > NULL);
> >  else
> >  imagedir = DATADIR "/lb/images";
> > }
> >
> > It's not clear what I am supposed to do with it. It reads "Now we just
> > change "IMAGEDIR" to "imagedir" in the
> >
> > window_pixbuf_fill_corner function and we're done. Let's test it!" I
> imagine
> > that I stick that function at the top
> > of the file and the change from IMAGEDIR to imagedir is the magic that
> glues
> > all this together?
>
> imagedir (lowercase) is a variable calculated at runtime. IMAGEDIR
> (uppercase) is a constant calculated at compile time.
>
> It doesn't matter where you put that code, as the __attribute__
> (constructor) thing will make sure that it gets called before any
> other function (as long as gcc is used to compile at least).
>
> -Isak
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: autopackage-dev-unsubscribe-OfajU3CKLf1/[email protected]
> For additional commands, e-mail: autopackage-dev-help-OfajU3CKLf1/[email protected]
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: autopackage-dev-unsubscribe-OfajU3CKLf1/[email protected]
For additional commands, e-mail: autopackage-dev-help-OfajU3CKLf1/[email protected]
lb-window.c (text/x-csrc, 27.5 KB)
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Copyright (C) 2005 Imendio AB
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 *  lb-window.c
 */

#include "config.h"

#include <string.h>

#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>

#include "lb-window.h"
#include "lb-item.h"
#include "lb-icon-box.h"
#include "lb-utils.h"
#include "lb-action.h"

#define FRAME_SIZE 30
#define SEARCH_TIMEOUT 150
#define SEARCH_RESET_TIMEOUT 2000

typedef enum {
	LB_WINDOW_CORNER_TOP_LEFT,
	LB_WINDOW_CORNER_TOP_RIGHT,
	LB_WINDOW_CORNER_BOTTOM_LEFT,
	LB_WINDOW_CORNER_BOTTOM_RIGHT
} LbWindowCorner;

typedef enum {
	LB_WINDOW_FOCUS_ITEM,
	LB_WINDOW_FOCUS_ACTION
} LbWindowFocus;

enum {
	COL_OBJECT,
	COL_PIXBUF,
	COL_NAME,
	NUM_COLS
};

enum {
	PROP_0,
	PROP_MANAGER,
};

typedef struct {
	LbModuleManager    *manager;

	LbWindowFocus       focus;

	GString            *search_string;

	LbItem             *current_item;
	LbAction           *current_action;

	GtkWidget          *result_hbox;

	GtkWidget          *item_icon_box;
	GtkWidget          *action_icon_box;

	GtkWidget          *result_treeview;

	GdkPixbuf          *empty_pixbuf;
	GdkPixbuf          *unknown_pixbuf;

	guint               search_timeout_id;
	
	gboolean            reset_search;
	guint               search_reset_timeout_id;
} LbWindowPriv;


static void     lb_window_finalize             (GObject           *object);
static void     lb_window_set_property         (GObject           *object,
						guint              property_id,
						const GValue      *value,
						GParamSpec        *pspec);
static void     lb_window_get_property         (GObject           *object,
						guint              property_id,
						GValue            *value,
						GParamSpec        *pspec);
static void     window_realize_cb              (GtkWidget         *widget,
						LbWindow          *window);
static void     window_set_focus               (LbWindow          *window,
						LbWindowFocus      focus);
static void     window_set_item                (LbWindow          *window,
						LbItem            *item,
						const gchar       *match);
static void     window_set_action              (LbWindow          *window,
						LbAction          *action,
						const gchar       *match);
static void     window_queue_search            (LbWindow          *window);
static gboolean window_search_timeout_cb       (LbWindow          *window);
static gboolean window_search_reset_timeout_cb (LbWindow          *window);
static void     window_perform_search          (LbWindow          *window,
						const gchar       *str);
static void     window_result_row_selected_cb  (GtkTreeSelection *selection,
						LbWindow          *window);
static void     window_reset_result            (LbWindow          *window);
static gboolean window_key_press_event_cb      (GtkWidget         *widget,
						GdkEventKey       *event,
						LbWindow          *window);
static gboolean window_get_is_visible          (LbWindow          *window);
static void     window_update_background       (LbWindow          *window);
static void     window_start_reset_timeout     (LbWindow          *window);


G_DEFINE_TYPE (LbWindow, lb_window, GTK_TYPE_WINDOW);
#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LB_TYPE_WINDOW, LbWindowPriv))


static void
lb_window_class_init (LbWindowClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);

	object_class->finalize     = lb_window_finalize;
	object_class->set_property = lb_window_set_property;
	object_class->get_property = lb_window_get_property;

	g_object_class_install_property (object_class, PROP_MANAGER,
					 g_param_spec_object ("manager",
							      NULL, NULL,
							      LB_TYPE_MODULE_MANAGER,
							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

	g_type_class_add_private (klass, sizeof (LbWindowPriv));
}

static void
lb_window_init (LbWindow *window)
{
	LbWindowPriv      *priv = GET_PRIV (window);
	GtkWidget         *vbox;
	GtkWidget         *sw;
	GtkListStore      *store;
	GtkTreeViewColumn *column;
	GtkCellRenderer   *cell;
	GtkTreeSelection  *selection;

	gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
	gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);

	priv->focus = LB_WINDOW_FOCUS_ITEM;

	priv->search_timeout_id = 0;
	priv->search_reset_timeout_id = 0;
	priv->reset_search = FALSE;

	priv->search_string = g_string_new (NULL);

	priv->empty_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
					     TRUE,
                                             8,
                                             64, 64);
	gdk_pixbuf_fill (priv->empty_pixbuf, 0x00000000);

	priv->unknown_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
					       TRUE,
					       8,
					       64, 64);
	gdk_pixbuf_fill (priv->unknown_pixbuf, 0x00000000);

	vbox = gtk_vbox_new (FALSE, 6);
	gtk_container_set_border_width (GTK_CONTAINER (vbox), 18);
	gtk_widget_show (vbox);

	gtk_container_add (GTK_CONTAINER (window), vbox);

	priv->result_hbox = gtk_hbox_new (FALSE, 12);
	gtk_widget_show (priv->result_hbox);
	gtk_box_pack_start (GTK_BOX (vbox),
			    priv->result_hbox, FALSE, FALSE, 0);

	priv->item_icon_box = lb_icon_box_new (NULL, priv->empty_pixbuf);
	gtk_frame_set_shadow_type (GTK_FRAME (priv->item_icon_box),
				   GTK_SHADOW_IN);
	gtk_widget_show (priv->item_icon_box);
	gtk_box_pack_start (GTK_BOX (priv->result_hbox), priv->item_icon_box,
			    TRUE, TRUE, 0);

	priv->action_icon_box = lb_icon_box_new (NULL, priv->empty_pixbuf);
	gtk_widget_show (priv->action_icon_box);
	gtk_box_pack_start (GTK_BOX (priv->result_hbox), priv->action_icon_box,
			    TRUE, TRUE, 0);

	sw = gtk_scrolled_window_new (NULL, NULL);
	gtk_widget_set_size_request (sw, -1, 64 * 4);
	gtk_widget_show (sw);

	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
					GTK_POLICY_AUTOMATIC,
					GTK_POLICY_AUTOMATIC);

	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
					     GTK_SHADOW_IN);

	priv->result_treeview = gtk_tree_view_new ();

	gtk_widget_show (priv->result_treeview);
	gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);

	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (priv->result_treeview), FALSE);

	gtk_container_add (GTK_CONTAINER (sw), priv->result_treeview);

	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->result_treeview), FALSE);

	store = gtk_list_store_new (NUM_COLS,
				    LB_TYPE_OBJECT,
				    GDK_TYPE_PIXBUF,
				    G_TYPE_STRING);

	gtk_tree_view_set_model (GTK_TREE_VIEW (priv->result_treeview),
				 GTK_TREE_MODEL (store));

	column = gtk_tree_view_column_new ();

	cell = gtk_cell_renderer_pixbuf_new ();
	gtk_tree_view_column_pack_start (column, cell, FALSE);

	gtk_tree_view_column_add_attribute (column,
					    cell,
					    "pixbuf",
					    COL_PIXBUF);

	cell = gtk_cell_renderer_text_new ();
	g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
	gtk_tree_view_column_pack_start (column, cell, TRUE);

	gtk_tree_view_column_add_attribute (column,
					    cell,
					    "markup",
					    COL_NAME);

	gtk_tree_view_append_column (GTK_TREE_VIEW (priv->result_treeview), column);

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->result_treeview));

	g_signal_connect (selection, "changed",
			  G_CALLBACK (window_result_row_selected_cb),
			  window);

	g_signal_connect (window, "key_press_event",
			  G_CALLBACK (window_key_press_event_cb),
			  window);

	g_signal_connect (window, "realize",
			  G_CALLBACK (window_realize_cb),
			  window);
}

static void
lb_window_finalize (GObject *object)
{
	LbWindow     *window = LB_WINDOW (object);
	LbWindowPriv *priv   = GET_PRIV (window);

	if (priv->search_timeout_id) {
		g_source_remove (priv->search_timeout_id);
	}

	if (priv->search_reset_timeout_id) {
		g_source_remove (priv->search_reset_timeout_id);
	}

	if (priv->current_item) {
		g_object_unref (priv->current_item);
	}
	if (priv->current_action) {
		g_object_unref (priv->current_action);
	}

	g_string_free (priv->search_string, TRUE);

	g_object_unref (priv->unknown_pixbuf);
	g_object_unref (priv->empty_pixbuf);

	G_OBJECT_CLASS (lb_window_parent_class)->finalize (object);
}

static void
lb_window_set_property (GObject      *object,
                        guint         property_id,
                        const GValue *value,
                        GParamSpec   *pspec)
{
	LbWindow     *window = LB_WINDOW (object);
	LbWindowPriv *priv   = GET_PRIV (window);

	switch (property_id) {
	case PROP_MANAGER:
		priv->manager = LB_MODULE_MANAGER (g_value_dup_object (value));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
lb_window_get_property (GObject    *object,
                        guint       property_id,
                        GValue     *value,
                        GParamSpec *pspec)
{
	LbWindow     *window = LB_WINDOW (object);
	LbWindowPriv *priv   = GET_PRIV (window);

	switch (property_id) {
	case PROP_MANAGER:
		g_value_set_object (value, priv->manager);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
window_realize_cb (GtkWidget *widget,
		   LbWindow  *window)
{
	window_update_background (LB_WINDOW (window));
}

GtkWidget *
lb_window_new (LbModuleManager *manager)
{
	GtkWidget *window;

	window = g_object_new (LB_TYPE_WINDOW,
			       "type", GTK_WINDOW_POPUP,
			       "manager", manager,
			       NULL);

	return window;
}

static void
window_set_focus (LbWindow      *window,
		  LbWindowFocus  focus)
{
	LbWindowPriv *priv = GET_PRIV (window);
	GtkListStore *store;

	if (priv->focus == focus) {
		return;
	}

	if (focus == LB_WINDOW_FOCUS_ACTION) {
		if (! priv->current_action) {
			return;
		}
	}

	store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->result_treeview)));
	gtk_list_store_clear (store);

	g_string_truncate (priv->search_string, 0);

	if (focus == LB_WINDOW_FOCUS_ACTION) {
		gtk_frame_set_shadow_type (GTK_FRAME (priv->item_icon_box),
					   GTK_SHADOW_NONE);
		gtk_frame_set_shadow_type (GTK_FRAME (priv->action_icon_box),
					   GTK_SHADOW_IN);
	} else {
		gtk_frame_set_shadow_type (GTK_FRAME (priv->item_icon_box),
					   GTK_SHADOW_IN);
		gtk_frame_set_shadow_type (GTK_FRAME (priv->action_icon_box),
					   GTK_SHADOW_NONE);
	}

	priv->focus = focus;

	window_queue_search (window);
}

static void
window_set_item (LbWindow    *window,
		 LbItem      *item,
		 const gchar *match)
{
	LbWindowPriv *priv = GET_PRIV (window);

	if (priv->current_item == item) {
		return;
	}

	if (priv->current_item) {
		g_object_unref (priv->current_item);
		priv->current_item = NULL;
	}

	if (item) {
		GdkPixbuf *pixbuf;
		gchar     *markup = NULL;
		GList     *actions;

		priv->current_item = g_object_ref (item);

		g_object_get (item, "pixbuf", &pixbuf, NULL);

		if (match) {
			markup = lb_string_markup_substring (LB_OBJECT (item)->name,
							     match, "u");
		}

		if (! markup) {
			markup = g_markup_escape_text (LB_OBJECT (item)->name,
						       -1);
		}

		g_object_set (priv->item_icon_box,
			      "caption", markup,
			      "pixbuf",  pixbuf ? pixbuf : priv->unknown_pixbuf,
			      NULL);

		if (pixbuf)
			g_object_unref (pixbuf);
		g_free (markup);

		actions = lb_item_get_actions (item, NULL);

		if (! actions) {
			lb_module_manager_set_actions (priv->manager, item);
			actions = lb_item_get_actions (item, NULL);
		}

		if (actions) {
			window_set_action (window, actions->data, NULL);

			g_list_free (actions);
		} else {
			window_set_action (window, NULL, NULL);
		}
	} else {
		g_object_set (priv->item_icon_box,
			      "caption", NULL,
			      "pixbuf",  priv->empty_pixbuf,
			      NULL);
		window_set_action (window, NULL, NULL);
	}
}

static void
window_set_action (LbWindow    *window,
		   LbAction    *action,
		   const gchar *match)
{
	LbWindowPriv *priv = GET_PRIV (window);

	if (priv->current_action == action) {
		return;
	}

	if (priv->current_action) {
		g_object_unref (priv->current_action);
		priv->current_action = NULL;
	}

	if (action) {
		GdkPixbuf *pixbuf;
		gchar     *markup = NULL;

		priv->current_action = g_object_ref (action);

		g_object_get (LB_OBJECT (action), "pixbuf", &pixbuf, NULL);

		if (match) {
			markup = lb_string_markup_substring (LB_OBJECT (action)->name,
							     match, "u");
		}

		if (! markup) {
			markup = g_markup_escape_text (LB_OBJECT (action)->name,
						       -1);
		}

		g_object_set (priv->action_icon_box,
			      "caption", markup,
			      "pixbuf",  pixbuf ? pixbuf : priv->unknown_pixbuf,
			      NULL);
		if (pixbuf)
			g_object_unref (pixbuf);
		g_free (markup);
	} else {
		g_object_set (priv->action_icon_box,
			      "caption", NULL,
			      "pixbuf",  priv->empty_pixbuf,
			      NULL);
	}
}

static void
window_queue_search (LbWindow *window)
{
	LbWindowPriv *priv = GET_PRIV (window);
	LbObject     *current;
	LbIconBox    *icon_box;

	if (priv->focus == LB_WINDOW_FOCUS_ITEM) {
		current  = LB_OBJECT (priv->current_item);
		icon_box = LB_ICON_BOX (priv->item_icon_box);
	} else {
		current  = LB_OBJECT (priv->current_action);
		icon_box = LB_ICON_BOX (priv->action_icon_box);
	}

	/* If we already have a match, try matching further on it. */
	if (current) {
		if (lb_string_has_substring (current->name,
					     priv->search_string->str)) {
			gchar *markup;

			markup = lb_string_markup_substring (current->name,
							     priv->search_string->str, "u");

			g_object_set (icon_box,
				      "caption", markup ? markup : current->name,
				      NULL);

			g_free (markup);
		} else {
			if (priv->focus == LB_WINDOW_FOCUS_ITEM) {
				window_set_item (window, NULL, NULL);
			} else {
				window_set_action (window, NULL, NULL);
			}

			g_object_set (icon_box,
				      "caption", priv->search_string->str,
				      NULL);
		}
	} else {
		g_object_set (icon_box,
			      "caption", priv->search_string->str,
			      NULL);
	}

	if (priv->search_timeout_id) {
		g_source_remove (priv->search_timeout_id);
	}

	priv->search_timeout_id = g_timeout_add (SEARCH_TIMEOUT,
						 (GSourceFunc) window_search_timeout_cb,
						 window);
}

static gboolean
window_search_timeout_cb (LbWindow *window)
{
	LbWindowPriv *priv = GET_PRIV (window);

	priv->search_timeout_id = 0;

	window_perform_search (window, priv->search_string->str);

	return FALSE;
}

static gboolean
window_search_reset_timeout_cb (LbWindow *window)
{
	LbWindowPriv *priv = GET_PRIV (window);

	priv->search_reset_timeout_id = 0;

	priv->reset_search = TRUE;
	return FALSE;
}

static void
window_perform_search (LbWindow    *window,
		       const gchar *str)
{
	LbWindowPriv     *priv;
	GList            *list, *l;
	GtkListStore     *store;
	GtkTreeSelection *selection;
	gboolean          selected = FALSE;

	priv = GET_PRIV (window);

	window_reset_result (window);

	if (str && str[0] == '\0') {
		str = NULL;
	}

	if (! str && priv->focus == LB_WINDOW_FOCUS_ITEM) {
		return;
	}

	if (priv->focus == LB_WINDOW_FOCUS_ITEM) {
		list = lb_module_manager_query (priv->manager, str);
	} else {
		list = lb_item_get_actions (priv->current_item, str);
	}

	if (!list) {
		return;
	}

	store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->result_treeview)));

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->result_treeview));

	for (l = list; l; l = l->next) {
		GtkTreeIter  iter;
		LbObject    *object;
		GdkPixbuf   *pixbuf;
		gchar       *markup;

		object = LB_OBJECT (l->data);

		markup = lb_string_markup_substring (object->name, str, "b");

		g_object_get (object, "pixbuf", &pixbuf, NULL);
		if (!pixbuf) {
			pixbuf = g_object_ref (priv->unknown_pixbuf);
		}

		gtk_list_store_append (store, &iter);
		gtk_list_store_set (store, &iter,
				    COL_OBJECT, object,
				    COL_PIXBUF, pixbuf,
				    COL_NAME,   markup ? markup : object->name,
				    -1);
		g_object_unref (pixbuf);
		g_free (markup);

		if (! selected) {
			gtk_tree_selection_select_iter (selection, &iter);
			selected = TRUE;
		}
	}

	g_list_free (list);
}

static void
window_result_row_selected_cb (GtkTreeSelection *selection,
			       LbWindow         *window)
{
	LbWindowPriv *priv = GET_PRIV (window);
	GtkTreeModel *model;
	GtkTreeIter   iter;

	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
		LbObject *object;

		gtk_tree_model_get (model, &iter,
				    COL_OBJECT, &object,
				    -1);

		if (priv->focus == LB_WINDOW_FOCUS_ITEM) {
			window_set_item (window, LB_ITEM (object),
					 priv->search_string->str);
		} else {
			window_set_action (window, LB_ACTION (object),
					   priv->search_string->str);
		}

		g_object_unref (object);
	}
}

static void
window_reset_result (LbWindow *window)
{
	LbWindowPriv *priv;
	GtkListStore *store;

	priv = GET_PRIV (window);

	priv->reset_search = FALSE;
	store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->result_treeview)));
	gtk_list_store_clear (store);

	if (priv->focus == LB_WINDOW_FOCUS_ITEM) {
		window_set_item (window, NULL, NULL);
		g_object_set (priv->item_icon_box,
			      "caption", priv->search_string->str, NULL);
	} else {
		window_set_action (window, NULL, NULL);
		g_object_set (priv->action_icon_box,
			      "caption", priv->search_string->str, NULL);
	}
}


/* Test some search stuff. */

static void
window_string_utf8_remove_last_char (GString *string)
{
	gchar *ptr;
	glong  utf8_len;

	utf8_len = g_utf8_strlen (string->str, -1);

	if (utf8_len == 0) {
		return;
	}

	utf8_len--;

	ptr = g_utf8_offset_to_pointer (string->str, utf8_len);

	g_string_truncate (string, string->len - strlen (ptr));
}

static gboolean
window_key_press_event_cb (GtkWidget   *widget,
			   GdkEventKey *event,
			   LbWindow    *window)
{
	LbWindowPriv *priv = GET_PRIV (window);

	if (event->state & GDK_CONTROL_MASK) {
		return TRUE;
	}

	switch (event->keyval) {
	case GDK_Escape:
		gtk_widget_hide (GTK_WIDGET (window));
		return TRUE;

	case GDK_BackSpace:
		if (priv->search_string->len == 0) {
			return TRUE;
		}

		window_string_utf8_remove_last_char (priv->search_string);
		window_queue_search (window);
		return TRUE;

	case GDK_Tab:
		if (priv->focus == LB_WINDOW_FOCUS_ITEM) {
			if (priv->current_action) {
				window_set_focus (window,
						  LB_WINDOW_FOCUS_ACTION);
			}
		} else {
			window_set_focus (window, LB_WINDOW_FOCUS_ITEM);
		}
		return TRUE;

	case GDK_Up:
	case GDK_Down: {
		GtkTreeView      *tv;
		GtkTreeSelection *selection;
		GtkTreeModel     *model;
		GtkTreeIter       iter;

		tv = GTK_TREE_VIEW (priv->result_treeview);

		selection = gtk_tree_view_get_selection (tv);

		if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
			GtkTreePath *path;

			path = gtk_tree_model_get_path (model, &iter);

			if (event->keyval == GDK_Up) {
				gtk_tree_path_prev (path);
			} else {
				gtk_tree_path_next (path);
			}

			gtk_tree_selection_select_path (selection, path);
			gtk_tree_view_scroll_to_cell (tv, path,
						      NULL, FALSE, 0.0, 0.0);
			gtk_tree_path_free (path);
		}
	}
		return TRUE;

	case GDK_Return:
	case GDK_ISO_Enter:
		if (priv->current_action) {
			lb_action_activate (priv->current_action);
		}
		gtk_widget_hide (GTK_WIDGET (window));

		return TRUE;

	default:
		if (priv->reset_search) {
			g_string_truncate (priv->search_string, 0);
			window_reset_result (window);
		}
		if (event->length > 0) {
			g_string_append_unichar (priv->search_string,
						 gdk_keyval_to_unicode (event->keyval));
		} else {
			return TRUE;
		}
	}
	
	window_queue_search (window);
	window_start_reset_timeout (window);
	
	return TRUE;
}

static gboolean
window_grab (LbWindow *window)
{
	GdkWindow *gdk_window;
	guint32    time;

	gdk_window = GTK_WIDGET (window)->window;
	time = gdk_x11_get_server_time (gdk_window);

	if ((gdk_pointer_grab (gdk_window, TRUE,
			       GDK_BUTTON_PRESS_MASK |
			       GDK_BUTTON_RELEASE_MASK |
			       GDK_POINTER_MOTION_MASK,
			       NULL, NULL, time) == 0)) {
		if (gdk_keyboard_grab (gdk_window, TRUE, time) == 0) {
			return TRUE;
		} else {
			gdk_pointer_ungrab (time);
			return FALSE;
		}
	}

	return FALSE;
}

void
lb_window_present (LbWindow *window)
{
	LbWindowPriv *priv = GET_PRIV (window);

	if (!window_get_is_visible (window)) {
		if (GTK_WIDGET_REALIZED (window)) {
			window_update_background (window);
		}

		g_string_truncate (priv->search_string, 0);
		window_reset_result (window);
		gtk_window_present (GTK_WINDOW (window));
	}

	if (!window_grab (window)) {
		/* g_print ("Couldn't grab.\n"); */
	}
}

static gchar *imagedir;

/* will be called automatically before main() */
static void __attribute__((constructor))
locate_image_dir () 
{
        if (gbr_init (NULL))
	        imagedir = g_build_filename (gbr_find_data_dir (DATADIR), "lb", "images", NULL);
        else
	        imagedir = DATADIR "/lb/images";
}

/*
 * Hack to get a transparent rounded window.
 */

static void
window_pixbuf_fill_middle (LbWindow  *window,
			   GdkPixbuf *pixbuf)
{
	gint       frame_width, frame_height;
	GdkPixbuf *piece;
	gint        width, height;

	frame_width = gdk_pixbuf_get_width (pixbuf);
	frame_height = gdk_pixbuf_get_height (pixbuf);

	width = frame_width - 2 * FRAME_SIZE;
	height = FRAME_SIZE;

	// Should this be patched? Neil
	filename = g_build_filename (imagedir, "lb-middle.png", NULL);
	piece = gdk_pixbuf_new_from_file_at_scale(filename, "lb-middle.png",
						   width, height,
						   FALSE,
						   NULL);
	g_return_if_fail (piece != NULL);

	gdk_pixbuf_copy_area (piece,
			      0, 0,
			      width, height,
			      pixbuf,
			      FRAME_SIZE, 0);

	gdk_pixbuf_copy_area (piece,
			      0, 0,
			      width, height,
			      pixbuf,
			      FRAME_SIZE, frame_height - FRAME_SIZE);

	g_object_unref (piece);

	width = FRAME_SIZE;
	height = frame_height - 2 * FRAME_SIZE;

	// Should this be patched? Neil
	filename = g_build_filename (imagedir, "lb-middle.png", NULL);
	piece = gdk_pixbuf_new_from_file_at_scale( filename, "lb-middle.png",
						   width, height,
						   FALSE,
						   NULL);
	g_return_if_fail (piece != NULL);

	gdk_pixbuf_copy_area (piece,
			      0, 0,
			      width, height,
			      pixbuf,
			      0, FRAME_SIZE);

	gdk_pixbuf_copy_area (piece,
			      0, 0,
			      width, height,
			      pixbuf,
			      frame_width - FRAME_SIZE, FRAME_SIZE);

	g_object_unref (piece);

	width = frame_width - 2 * FRAME_SIZE;
	height = frame_height - 2 * FRAME_SIZE;

	// Should this be patched? Neil
	filename = g_build_filename (imagedir, "lb-middle.png", NULL);
	piece = gdk_pixbuf_new_from_file_at_scale( filename, "lb-middle.png",
						   width, height,
						   FALSE,
						   NULL);
	g_return_if_fail (piece != NULL);

	gdk_pixbuf_copy_area (piece,
			      0, 0,
			      width, height,
			      pixbuf,
			      FRAME_SIZE, FRAME_SIZE);

	g_object_unref (piece);
	g_free( filename );
}

static void
window_pixbuf_fill_corner (LbWindow       *window,
			   GdkPixbuf      *pixbuf,
			   LbWindowCorner  corner)
{
	gint         frame_width, frame_height;
	GdkPixbuf   *piece;
	gint         width, height;
	const gchar *filename;
	gint         x, y;

	frame_width = gdk_pixbuf_get_width (pixbuf);
	frame_height = gdk_pixbuf_get_height (pixbuf);

	// Changed the below, as the tutorial showed me.
	switch (corner) {
	case LB_WINDOW_CORNER_TOP_LEFT:
		filename = g_build_filename( imagedir, "lb-top-left.png", NULL );
		break;
	case LB_WINDOW_CORNER_TOP_RIGHT:
		filename = g_build_filename( imagedir, "lb-top-right.png", NULL );
		break;
	case LB_WINDOW_CORNER_BOTTOM_LEFT:
		filename = g_build_filename( imagedir, "lb-bottom-left.png", NULL );
		break;
	case LB_WINDOW_CORNER_BOTTOM_RIGHT:
		filename = g_build_filename( imagedir, "lb-bottom-right.png", NULL );
		break;

	default:
		filename = NULL;
		g_assert_not_reached ();
	}

	piece = gdk_pixbuf_new_from_file (filename, NULL);
	g_return_if_fail (piece != NULL);

	width = gdk_pixbuf_get_width (piece);
	height = gdk_pixbuf_get_height (piece);

	switch (corner) {
	case LB_WINDOW_CORNER_TOP_LEFT:
		x = 0;
		y = 0;
		break;
	case LB_WINDOW_CORNER_TOP_RIGHT:
		x = frame_width - width;
		y = 0;
		break;
	case LB_WINDOW_CORNER_BOTTOM_LEFT:
		x = 0;
		y = frame_height - height;
		break;
	case LB_WINDOW_CORNER_BOTTOM_RIGHT:
		x = frame_width - width;
		y = frame_height - height;
		break;

	default:
		x = 0;
		y = 0;
		g_assert_not_reached ();
	}

	gdk_pixbuf_copy_area (piece,
			      0, 0,
			      width, height,
			      pixbuf,
			      x, y);

	g_object_unref (piece);
}

static void
window_pixbuf_overlay_frame (LbWindow *window, GdkPixbuf *pixbuf)
{
	GdkPixbuf *tmp;
	gint       frame_width, frame_height;

	frame_width = gdk_pixbuf_get_width (pixbuf);
	frame_height = gdk_pixbuf_get_height (pixbuf);

	tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
			      TRUE,
			      8,
			      frame_width, frame_height);

	gdk_pixbuf_fill (tmp, 0x00000000);

	window_pixbuf_fill_corner (window,
				   tmp,
				   LB_WINDOW_CORNER_TOP_LEFT);
	window_pixbuf_fill_corner (window,
				   tmp,
				   LB_WINDOW_CORNER_TOP_RIGHT);
	window_pixbuf_fill_corner (window,
				   tmp,
				   LB_WINDOW_CORNER_BOTTOM_LEFT);
	window_pixbuf_fill_corner (window,
				   tmp,
				   LB_WINDOW_CORNER_BOTTOM_RIGHT);

	window_pixbuf_fill_middle (window, tmp);

	gdk_pixbuf_composite (tmp,
			      pixbuf,
			      0, 0,
			      frame_width, frame_height,
			      0, 0, /* offset */
			      1, 1, /* scale */
			      GDK_INTERP_NEAREST,
			      225);
}

static gboolean
window_get_is_visible (LbWindow *window)
{
	gboolean visible;

	g_object_get (window,
		      "visible", &visible,
		      NULL);
	
	if (GTK_WIDGET (window)->window) {
		visible = visible && !(gdk_window_get_state (GTK_WIDGET (window)->window) & GDK_WINDOW_STATE_ICONIFIED);
	}
	
	return visible;
}

static void
window_update_background (LbWindow *window)
{
	LbWindowPriv *priv;
	GdkScreen    *screen;
	GdkPixbuf    *pixbuf;
	gint          screen_width, screen_height;
	gint          x, y;
	gint          width, height;
	GdkPixmap    *pixmap;

	priv = GET_PRIV (window);

	screen = gtk_widget_get_screen (GTK_WIDGET (window));

	gtk_window_get_size (GTK_WINDOW (window), &width, &height);

	screen_width = gdk_screen_get_width (screen);
	screen_height = gdk_screen_get_height (screen);

	x = screen_width / 2 - width / 2;
	y = screen_height / 2 - height / 2;

	pixbuf = gdk_pixbuf_get_from_drawable (
		NULL,
		gdk_screen_get_root_window (screen),
		gdk_screen_get_system_colormap (screen),
		x, y,
		0, 0,
		width, height);

	g_assert (pixbuf != NULL);

	gtk_window_move (GTK_WINDOW (window), x, y);

	window_pixbuf_overlay_frame (window, pixbuf);

	/* Put the resulting image on the window. */
	pixmap = gdk_pixmap_new (GTK_WIDGET (window)->window,
				 width,
				 height,
				 -1);

	gdk_draw_pixbuf (pixmap,
			 NULL, /* clipping gc */
			 pixbuf,
			 0, 0, /* src */
			 0, 0, /* dst */
			 width, height,
			 GDK_RGB_DITHER_NONE,
			 0, 0);

	gdk_window_set_back_pixmap (GTK_WIDGET (window)->window, pixmap, FALSE);

	g_object_unref (pixbuf);
	g_object_unref (pixmap);

	gtk_widget_queue_draw (GTK_WIDGET (window));
}

static void
window_start_reset_timeout (LbWindow *window)
{
	LbWindowPriv *priv = GET_PRIV (window);

	if (priv->search_reset_timeout_id) {
		g_source_remove (priv->search_reset_timeout_id);
	}

	priv->search_reset_timeout_id = g_timeout_add (SEARCH_RESET_TIMEOUT,
						       (GSourceFunc) window_search_reset_timeout_cb,
						       window);
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.