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
|
bin_PROGRAMS = lookuplet
|
||||||
|
|
||||||
@@ -9,7 +9,8 @@ lookuplet_SOURCES = \
|
|||||||
querybox.c \
|
querybox.c \
|
||||||
preferences.c \
|
preferences.c \
|
||||||
binding.c \
|
binding.c \
|
||||||
keysym-util.c
|
keysym-util.c \
|
||||||
|
history.c
|
||||||
|
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
-I. \
|
-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
|
* lookuplet - a utility for quickly looking up information
|
||||||
* Copyright (C) 2001 Michael Bayne
|
* Copyright (C) 2001 Michael Bayne
|
||||||
@@ -84,7 +84,7 @@ main (int argc, char** argv)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (applet_mode) {
|
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() */
|
call gnome_init() */
|
||||||
applet_widget_init(PACKAGE, VERSION, argc, argv, NULL, 0, NULL);
|
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
|
* lookuplet - a utility for quickly looking up information
|
||||||
* Copyright (C) 2001 Michael Bayne
|
* Copyright (C) 2001 Michael Bayne
|
||||||
@@ -27,16 +27,25 @@
|
|||||||
|
|
||||||
#include "binding.h"
|
#include "binding.h"
|
||||||
#include "launcher.h"
|
#include "launcher.h"
|
||||||
|
#include "history.h"
|
||||||
#include "keysym-util.h"
|
#include "keysym-util.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "lookuplet.h"
|
#include "lookuplet.h"
|
||||||
#include "querybox.h"
|
#include "querybox.h"
|
||||||
|
|
||||||
|
/* the query text entry field */
|
||||||
static GtkWidget* _query;
|
static GtkWidget* _query;
|
||||||
|
|
||||||
/* used by url_p */
|
/* used by url_p */
|
||||||
#define MATCH_PREFIX(text, prefix) !strncmp(text, prefix, sizeof(prefix)-1)
|
#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
|
* A very primitive function to try to determine if the selection is a URL
|
||||||
* of some sort.
|
* 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
|
static gint
|
||||||
key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data)
|
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;
|
gint handled = FALSE, i;
|
||||||
gchar* keystr;
|
gchar* keystr;
|
||||||
|
|
||||||
|
/* handle special keystrokes such as history and auto-complete */
|
||||||
|
if (handle_special_keys(widget, ek)) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* ignore plain or shifted keystrokes */
|
/* ignore plain or shifted keystrokes */
|
||||||
if (ek->state <= 1) {
|
if (ek->state <= 1) {
|
||||||
return FALSE;
|
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 */
|
/* otherwise convert the key combo to a name and look it up */
|
||||||
keystr = convert_keysym_state_to_string(ek->keyval, ek->state);
|
keystr = convert_keysym_state_to_string(ek->keyval, ek->state);
|
||||||
|
if (keystr == NULL) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
bindings = lk_prefs_get_bindings();
|
bindings = lk_prefs_get_bindings();
|
||||||
|
|
||||||
for (i = 0; i < bindings->len; i++) {
|
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 */
|
/* get the terms from the query box */
|
||||||
gchar* search_text =
|
gchar* search_text =
|
||||||
gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
|
gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
|
||||||
|
/* save this entry in the history */
|
||||||
|
lk_add_history(search_text);
|
||||||
/* launch the appropriate thing */
|
/* launch the appropriate thing */
|
||||||
lk_launcher_launch(binding, search_text);
|
lk_launcher_launch(binding, search_text);
|
||||||
g_free(search_text);
|
g_free(search_text);
|
||||||
if (applet_mode) {
|
if (applet_mode) {
|
||||||
/* clear out the contents of the entry box */
|
/* clear out the contents of the entry box */
|
||||||
gtk_entry_set_text(GTK_ENTRY(widget), "");
|
gtk_entry_set_text(GTK_ENTRY(widget), "");
|
||||||
@@ -151,9 +205,11 @@ launch (GtkWidget* widget, gpointer data)
|
|||||||
* instead of pressing some special key combination) */
|
* instead of pressing some special key combination) */
|
||||||
gchar* search_text = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
|
gchar* search_text = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
|
||||||
lk_launcher_launch(NULL, search_text);
|
lk_launcher_launch(NULL, search_text);
|
||||||
g_free(search_text);
|
|
||||||
|
|
||||||
if (applet_mode) {
|
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 */
|
/* clear out the contents of the entry box */
|
||||||
gtk_entry_set_text(GTK_ENTRY(widget), "");
|
gtk_entry_set_text(GTK_ENTRY(widget), "");
|
||||||
} else {
|
} else {
|
||||||
@@ -195,6 +251,9 @@ lk_querybox_create (void)
|
|||||||
gtk_box_pack_start(GTK_BOX(hbox), prefs, FALSE, FALSE, 0);
|
gtk_box_pack_start(GTK_BOX(hbox), prefs, FALSE, FALSE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* create the array of history commands */
|
||||||
|
lk_init_history();
|
||||||
|
|
||||||
return hbox;
|
return hbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user