Re: Help packaging the latest pidgin.

"Neil Munro" <[email protected]>
Newsgroups gmane.comp.autopackage.devel
Message-ID <[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);

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."

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.

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?

Thanks
Neil Munro



On 31/01/2008, Isak Savo <[email protected]> wrote:
>
> 2008/1/31, Neil Munro <[email protected]>:
> > Ok, how do I go about doing this secondary method then? I downloaded the
> .c
> > file, but can't compile it :S I understand the abstract concept of what
> I am
> > doing, but not the practical aspect, I really do need some practical
> help,
> > if someone can show me a small project to get my toes wet with or
> something
>
> It's really not much more to it than the abstract concept. :)
>
> The practical issues are typically:
> Find all places in the code which does things like
>    image = load_image (DATADIR "/images/myimage.png");
> with
>    gchar *datadir = gbr_find_datadir (DATADIR);
>    gchar *imagepath = g_build_filename (datadir, "images", "myimage.png");
>    image = load_image (imagepath);
>
> and put a gbr_init() call somewhere in the beginning of main().
>
> To see some real world cases were binreloc is used, just dive into any
> of the autopackage binaries, like mkapspec, gladecompat, autosu-gtk
> and autosu-tui.
>
> -Isak
> -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 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"); */
	}
}

/*
 * 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
	piece = gdk_pixbuf_new_from_file_at_scale (IMAGEDIR "/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
	piece = gdk_pixbuf_new_from_file_at_scale (IMAGEDIR "/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
	piece = gdk_pixbuf_new_from_file_at_scale (IMAGEDIR "/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);
}

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.