Added history and tab-completion based on the history contents. Fixed
potential segmentation fault if key symbol translation fails. git-svn-id: https://samskivert.googlecode.com/svn/trunk@650 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# $Id: Makefile.am,v 1.4 2001/08/18 02:34:06 mdb Exp $
|
||||
# $Id: Makefile.am,v 1.5 2002/03/14 16:45:26 shaper Exp $
|
||||
|
||||
bin_PROGRAMS = lookuplet
|
||||
|
||||
@@ -9,7 +9,8 @@ lookuplet_SOURCES = \
|
||||
querybox.c \
|
||||
preferences.c \
|
||||
binding.c \
|
||||
keysym-util.c
|
||||
keysym-util.c \
|
||||
history.c
|
||||
|
||||
INCLUDES = \
|
||||
-I. \
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* $Id: history.c,v 1.1 2002/03/14 16:45:26 shaper Exp $
|
||||
*
|
||||
* lookuplet - a utility for quickly looking up information
|
||||
* Copyright (C) 2001 Michael Bayne
|
||||
*
|
||||
* This program 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.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program 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 program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <gnome.h>
|
||||
|
||||
#include "history.h"
|
||||
|
||||
/* the array of historical entries */
|
||||
static gchar** _history;
|
||||
|
||||
/* the last entry index retrieved */
|
||||
static int _ridx = 0;
|
||||
|
||||
/* the insertion index for new history items */
|
||||
static int _iidx = 0;
|
||||
|
||||
/* the number of entries saved in the text entry history */
|
||||
#define HISTORY_COUNT (10)
|
||||
|
||||
void
|
||||
lk_init_history (void)
|
||||
{
|
||||
/* allocate and initialize the array of history entries */
|
||||
size_t size = sizeof(gchar*) * HISTORY_COUNT;
|
||||
_history = g_malloc(size);
|
||||
memset(_history, (int)NULL, size);
|
||||
}
|
||||
|
||||
const gchar*
|
||||
lk_get_history (gboolean next)
|
||||
{
|
||||
int actidx;
|
||||
|
||||
/* make sure the array is available */
|
||||
if (_history == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* determine the sought-after index */
|
||||
actidx = _ridx + ((next) ? -1 : 1);
|
||||
|
||||
/* make sure the index is valid and an entry exists */
|
||||
if (actidx < 0 || actidx >= HISTORY_COUNT || _history[actidx] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* update the retrieved index */
|
||||
_ridx = actidx;
|
||||
|
||||
return _history[actidx];
|
||||
}
|
||||
|
||||
const gchar*
|
||||
lk_get_history_expand (const gchar* entry)
|
||||
{
|
||||
int i, len;
|
||||
|
||||
if (_history == NULL || entry == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = strlen(entry);
|
||||
for (i = _iidx; i >= 0; i--) {
|
||||
gchar* str = _history[i];
|
||||
if (str != NULL && !g_strncasecmp(str, entry, len)) {
|
||||
/* update the retrieved index for potential subsequent retrievals */
|
||||
_ridx = i;
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lk_add_history (const gchar* entry)
|
||||
{
|
||||
/* make sure the array is available and the entry is valid */
|
||||
if (_history == NULL || entry == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* if there's no space remaining, shift off the oldest entry */
|
||||
if (_iidx == HISTORY_COUNT - 1 && _history[_iidx] != NULL) {
|
||||
g_free(_history[0]);
|
||||
memmove(_history, _history + 1, sizeof(gchar*) * (HISTORY_COUNT - 1));
|
||||
_history[_iidx] = NULL;
|
||||
}
|
||||
|
||||
/* remember the new entry */
|
||||
_history[_iidx] = g_strdup(entry);
|
||||
|
||||
/* increment the insertion and retrieved index */
|
||||
if (_iidx < HISTORY_COUNT - 1) {
|
||||
_iidx++;
|
||||
_ridx = _iidx;
|
||||
} else {
|
||||
_ridx = HISTORY_COUNT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* $Id: history.h,v 1.1 2002/03/14 16:45:26 shaper Exp $
|
||||
*
|
||||
* lookuplet - a utility for quickly looking up information
|
||||
* Copyright (C) 2001 Michael Bayne
|
||||
*
|
||||
* This program 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.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program 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 program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _HISTORY_H_
|
||||
#define _HISTORY_H_
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/**
|
||||
* Initializes the history storage.
|
||||
*/
|
||||
void
|
||||
lk_init_history (void);
|
||||
|
||||
/**
|
||||
* Returns the next history entry if next is true, else returns the
|
||||
* previous history entry.
|
||||
*/
|
||||
const gchar*
|
||||
lk_get_history (gboolean next);
|
||||
|
||||
/**
|
||||
* Returns the most recent history entry that matches the specified
|
||||
* partial entry text, or NULL if there are no matches. String
|
||||
* comparisons are case-insensitive as this is intended for use in
|
||||
* effecting auto-completion of sloppily-inputted partial entries. If a
|
||||
* matching entry is found, the current history item index is set to point
|
||||
* to that entry such that subsequent history entry retrievals will
|
||||
* automagically pick up from that point.
|
||||
*/
|
||||
const gchar*
|
||||
lk_get_history_expand (const gchar* entry);
|
||||
|
||||
/**
|
||||
* Adds an entry to the history and resets the current history item index
|
||||
* to point to the new entry.
|
||||
*/
|
||||
void
|
||||
lk_add_history (const gchar* entry);
|
||||
|
||||
#endif /* _HISTORY_H_ */
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* $Id: lookuplet.c,v 1.6 2001/08/18 02:34:06 mdb Exp $
|
||||
* $Id: lookuplet.c,v 1.7 2002/03/14 16:45:26 shaper Exp $
|
||||
*
|
||||
* lookuplet - a utility for quickly looking up information
|
||||
* Copyright (C) 2001 Michael Bayne
|
||||
@@ -84,7 +84,7 @@ main (int argc, char** argv)
|
||||
#endif
|
||||
|
||||
if (applet_mode) {
|
||||
/* intialize; this will basically set up the applet, corba and
|
||||
/* initialize; this will basically set up the applet, corba and
|
||||
call gnome_init() */
|
||||
applet_widget_init(PACKAGE, VERSION, argc, argv, NULL, 0, NULL);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* $Id: querybox.c,v 1.8 2001/08/21 18:46:10 mdb Exp $
|
||||
* $Id: querybox.c,v 1.9 2002/03/14 16:45:26 shaper Exp $
|
||||
*
|
||||
* lookuplet - a utility for quickly looking up information
|
||||
* Copyright (C) 2001 Michael Bayne
|
||||
@@ -27,16 +27,25 @@
|
||||
|
||||
#include "binding.h"
|
||||
#include "launcher.h"
|
||||
#include "history.h"
|
||||
#include "keysym-util.h"
|
||||
#include "preferences.h"
|
||||
#include "lookuplet.h"
|
||||
#include "querybox.h"
|
||||
|
||||
/* the query text entry field */
|
||||
static GtkWidget* _query;
|
||||
|
||||
/* used by url_p */
|
||||
#define MATCH_PREFIX(text, prefix) !strncmp(text, prefix, sizeof(prefix)-1)
|
||||
|
||||
/* key codes for navigating the entry history */
|
||||
#define NEXT_HISTORY_KEY (GDK_Up)
|
||||
#define PREVIOUS_HISTORY_KEY (GDK_Down)
|
||||
|
||||
/* key code for auto-completion of a partial entry */
|
||||
#define AUTO_COMPLETE_KEY (GDK_Tab)
|
||||
|
||||
/**
|
||||
* A very primitive function to try to determine if the selection is a URL
|
||||
* of some sort.
|
||||
@@ -95,6 +104,41 @@ selection_received (GtkWidget* widget, GtkSelectionData* selection_data,
|
||||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
handle_special_keys (GtkWidget* widget, GdkEventKey* ek)
|
||||
{
|
||||
const gchar* entry = NULL;
|
||||
|
||||
switch (ek->keyval) {
|
||||
case NEXT_HISTORY_KEY:
|
||||
case PREVIOUS_HISTORY_KEY:
|
||||
/* retrieve the sought-after historical entry */
|
||||
entry = lk_get_history(ek->keyval == NEXT_HISTORY_KEY);
|
||||
break;
|
||||
|
||||
case AUTO_COMPLETE_KEY: {
|
||||
/* get the terms from the query box */
|
||||
gchar* text = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
|
||||
/* seek an expanded historical entry for the current text */
|
||||
entry = lk_get_history_expand(text);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we've an entry, fill it in and we're done */
|
||||
if (entry != NULL) {
|
||||
/* place the entry in the text field */
|
||||
gtk_entry_set_text(GTK_ENTRY(widget), entry);
|
||||
|
||||
/* select the text in the entry so that it can be easily replaced */
|
||||
gtk_editable_select_region(GTK_EDITABLE(_query), 0, strlen(entry));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gint
|
||||
key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data)
|
||||
{
|
||||
@@ -103,6 +147,11 @@ key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data)
|
||||
gint handled = FALSE, i;
|
||||
gchar* keystr;
|
||||
|
||||
/* handle special keystrokes such as history and auto-complete */
|
||||
if (handle_special_keys(widget, ek)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ignore plain or shifted keystrokes */
|
||||
if (ek->state <= 1) {
|
||||
return FALSE;
|
||||
@@ -110,6 +159,9 @@ key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data)
|
||||
|
||||
/* otherwise convert the key combo to a name and look it up */
|
||||
keystr = convert_keysym_state_to_string(ek->keyval, ek->state);
|
||||
if (keystr == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
bindings = lk_prefs_get_bindings();
|
||||
|
||||
for (i = 0; i < bindings->len; i++) {
|
||||
@@ -118,9 +170,11 @@ key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data)
|
||||
/* get the terms from the query box */
|
||||
gchar* search_text =
|
||||
gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
|
||||
/* save this entry in the history */
|
||||
lk_add_history(search_text);
|
||||
/* launch the appropriate thing */
|
||||
lk_launcher_launch(binding, search_text);
|
||||
g_free(search_text);
|
||||
g_free(search_text);
|
||||
if (applet_mode) {
|
||||
/* clear out the contents of the entry box */
|
||||
gtk_entry_set_text(GTK_ENTRY(widget), "");
|
||||
@@ -151,9 +205,11 @@ launch (GtkWidget* widget, gpointer data)
|
||||
* instead of pressing some special key combination) */
|
||||
gchar* search_text = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
|
||||
lk_launcher_launch(NULL, search_text);
|
||||
g_free(search_text);
|
||||
|
||||
if (applet_mode) {
|
||||
/* save this entry in the history */
|
||||
lk_add_history(search_text);
|
||||
g_free(search_text);
|
||||
/* clear out the contents of the entry box */
|
||||
gtk_entry_set_text(GTK_ENTRY(widget), "");
|
||||
} else {
|
||||
@@ -195,6 +251,9 @@ lk_querybox_create (void)
|
||||
gtk_box_pack_start(GTK_BOX(hbox), prefs, FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
/* create the array of history commands */
|
||||
lk_init_history();
|
||||
|
||||
return hbox;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user