/*
* Maketool - GTK-based front end for gmake
* Copyright (c) 1999-2003 Greg Banks
*
* 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 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 "maketool.h"
#include "filter.h"
#include "maketool_task.h"
#include "ui.h"
#include "util.h"
#include <gdk/gdkkeysyms.h>
CVSID("$Id: help.c,v 1.44 2003/09/29 01:07:20 gnb Exp $");
static GtkWidget *licence_shell = 0;
static GtkWidget *options_shell = 0;
static GtkWidget *about_shell = 0;
static GtkWidget *about_make_shell = 0;
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*
* Hmm, the string literal from Hell. I hope this doesn't give
* your compiler conniptions. Contact me if it does -- Greg
*/
static const char licence_str[] =
#include "licence.c"
;
static void
licence_cb(GtkWidget *w, gpointer data)
{
if (licence_shell == 0)
{
GtkWidget *hbox, *text, *sb;
licence_shell = ui_create_ok_dialog(toplevel, _("Maketool: Licence"));
ui_set_help_tag(licence_shell, "licence-window");
gtk_widget_set_usize(licence_shell, 590, 300);
hbox = gtk_hbox_new(FALSE, SPACING);
gtk_container_border_width(GTK_CONTAINER(hbox), SPACING);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(licence_shell)->vbox), hbox);
gtk_widget_show(hbox);
text = gtk_text_new(0, 0);
gtk_text_set_editable(GTK_TEXT(text), FALSE);
gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, TRUE, 0);
gtk_widget_show(text);
sb = gtk_vscrollbar_new(GTK_TEXT(text)->vadj);
gtk_box_pack_start(GTK_BOX(hbox), sb, FALSE, FALSE, 0);
gtk_widget_show(sb);
gtk_text_insert(GTK_TEXT(text), 0, 0, 0,
licence_str, sizeof(licence_str)-1);
}
gtk_widget_show(licence_shell);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
build_options_string(estring *e)
{
int i;
filter_describe_all(e, /*lod*/1, " ");
estring_append_string(e, "Makefile systems:\n");
for (i = 0 ; makesystems[i] ; i++)
estring_append_printf(e, " %s\n", _(makesystems[i]->label));
estring_append_string(e, "Make programs:\n");
for (i = 0 ; makeprograms[i] ; i++)
estring_append_printf(e, " %s\n", _(makeprograms[i]->label));
}
static void
options_cb(GtkWidget *w, gpointer data)
{
if (options_shell == 0)
{
GtkWidget *hbox, *text, *sb;
estring options_str;
options_shell = ui_create_ok_dialog(toplevel, _("Maketool: Compile Options"));
ui_set_help_tag(options_shell, "compile-options-window");
gtk_widget_set_usize(options_shell, 450, 300);
hbox = gtk_hbox_new(FALSE, SPACING);
gtk_container_border_width(GTK_CONTAINER(hbox), SPACING);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(options_shell)->vbox), hbox);
gtk_widget_show(hbox);
text = gtk_text_new(0, 0);
gtk_text_set_editable(GTK_TEXT(text), FALSE);
gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, TRUE, 0);
gtk_widget_show(text);
sb = gtk_vscrollbar_new(GTK_TEXT(text)->vadj);
gtk_box_pack_start(GTK_BOX(hbox), sb, FALSE, FALSE, 0);
gtk_widget_show(sb);
estring_init(&options_str);
build_options_string(&options_str);
gtk_text_insert(GTK_TEXT(text), 0, 0, 0,
options_str.data, options_str.length);
estring_free(&options_str);
}
gtk_widget_show(options_shell);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
#include "maketool_l.xpm"
static const char warranty_str[] = N_("\
Maketool comes with ABSOLUTELY NO WARRANTY;\n\
for details press the Licence button. This is free\n\
software, and you are welcome to redistribute it\n\
under certain conditions; press the Licence button\n\
for details.\
");
static const char about_str[] = "\
Maketool version %s\n\
\n\
(c) 1999-2003 Greg Banks\n\
<gnb@alphalink.com.au>\n\
\n\
%s";
void
help_about_cb(GtkWidget *w, gpointer data)
{
if (about_shell == 0)
{
GtkWidget *label;
GtkWidget *icon;
GtkWidget *hbox;
GdkPixmap *pm;
GdkBitmap *mask;
char *abt;
about_shell = ui_create_ok_dialog(toplevel, _("Maketool: About"));
ui_set_help_tag(about_shell, "about-maketool-window");
hbox = gtk_hbox_new(FALSE, 5);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(about_shell)->vbox), hbox);
gtk_container_border_width(GTK_CONTAINER(hbox), SPACING);
gtk_widget_show(hbox);
pm = gdk_pixmap_create_from_xpm_d(toplevel->window,
&mask, 0, maketool_l_xpm);
icon = gtk_pixmap_new(pm, mask);
gtk_container_add(GTK_CONTAINER(hbox), icon);
gtk_widget_show(icon);
/* Build the string to display in the About box */
abt = g_strdup_printf(about_str, VERSION, _(warranty_str));
label = gtk_label_new(abt);
g_free(abt);
gtk_container_add(GTK_CONTAINER(hbox), label);
gtk_widget_show(label);
ui_dialog_create_button(about_shell, _("Options..."), options_cb, (gpointer)0);
ui_dialog_create_button(about_shell, _("Licence..."), licence_cb, (gpointer)0);
}
gtk_widget_show(about_shell);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static estring make_version = ESTRING_STATIC_INIT;
static const MakeProgram *make_version_makeprog;
static void
make_version_input(Task *task, int len, const char *buf)
{
estring_append_chars(&make_version, buf, len);
#if DEBUG
fprintf(stderr, "make_version_input(): make_version=\"%s\"\n",
make_version.data);
#endif
}
static void
create_about_make_shell(void)
{
GtkWidget *label;
GtkWidget *hbox;
char *title;
title = g_strdup_printf(_("Maketool: About %s"), makeprog->label);
about_make_shell = ui_create_ok_dialog(toplevel, title);
ui_set_help_tag(about_make_shell, "about-make-window");
g_free(title);
hbox = gtk_hbox_new(FALSE, 5);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(about_make_shell)->vbox), hbox);
gtk_container_border_width(GTK_CONTAINER(hbox), SPACING);
gtk_widget_show(hbox);
if (makeprog->logo_xpm != 0)
{
GdkPixmap *pm;
GdkBitmap *mask;
GtkWidget *icon;
pm = gdk_pixmap_create_from_xpm_d(toplevel->window,
&mask, 0, (char **)makeprog->logo_xpm);
icon = gtk_pixmap_new(pm, mask);
gtk_container_add(GTK_CONTAINER(hbox), icon);
gtk_widget_show(icon);
}
label = gtk_label_new(make_version.data);
gtk_container_add(GTK_CONTAINER(hbox), label);
gtk_widget_show(label);
}
static void
make_version_reap(Task *task)
{
if (about_make_shell == 0)
create_about_make_shell();
gtk_widget_show(about_make_shell);
}
static TaskOps make_version_ops =
{
0, /* start */
make_version_input, /* input */
make_version_reap, /* reap */
0 /* destroy */
};
static Task *
make_version_task(void)
{
return task_create(
(Task *)g_new(Task, 1),
expand_prog(prefs.prog_list_version, 0, 0, 0),
prefs.var_environment,
&make_version_ops,
0);
}
void
help_about_make_cb(GtkWidget *w, gpointer data)
{
/* TODO: grey out menu item while make --version running */
if (make_version.data == 0 ||
make_version_makeprog != makeprog)
{
/*
* First time, or makeprog has been changed since last time.
* Haven't yet extracted version info from `make',
* so start `make' and delay creation of dialog box until we
* have the output, i.e. in the reap function.
*/
if (about_make_shell != 0)
{
gtk_widget_destroy(about_make_shell);
about_make_shell = 0;
}
estring_truncate(&make_version);
make_version_makeprog = makeprog;
task_spawn(make_version_task());
}
else
{
if (about_make_shell == 0)
create_about_make_shell();
gtk_widget_show(about_make_shell);
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static gboolean help_initialised = FALSE;
#define HELP_NUM_LOCALES 4
static char *help_locales[HELP_NUM_LOCALES];
static GHashTable *help_indexes[HELP_NUM_LOCALES];
static void
help_init_locales(void)
{
/* initialise searchlist of locales */
const char *loc;
int i;
char langbuf[3];
loc = getenv("LC_MESSAGES");
if (loc == 0)
loc = getenv("LANG");
i = 0;
if (loc != 0)
{
help_locales[i++] = g_strdup(loc);
if (strlen(loc) > 2 && loc[2] == '_')
{
langbuf[0] = loc[0];
langbuf[1] = loc[1];
langbuf[2] = '\0';
help_locales[i++] = g_strdup(langbuf);
}
}
if (loc == 0 || strcmp(loc, "C"))
help_locales[i++] = g_strdup("C");
help_locales[i] = 0;
assert(i < HELP_NUM_LOCALES);
#if DEBUG > 2
fprintf(stderr, "help_init_locales: search locales:");
for (i=0 ; help_locales[i] != 0 ; i++)
fprintf(stderr, " \"%s\"", help_locales[i]);
fprintf(stderr, "\n");
#endif
}
static GHashTable *
help_read_index(const char *filename)
{
FILE *fp;
char *tag, *urlpart;
GHashTable *hash = 0;
char buf[1024];
static const char sep[] = " \t\n\r";
if ((fp = fopen(filename, "r")) == 0)
{
if (errno != ENOENT)
perror(filename);
return 0;
}
while (fgets(buf, sizeof(buf), fp) != 0)
{
if (buf[0] == '#')
continue; /* skip comment lines */
if ((tag = strtok(buf, sep)) == 0)
continue;
if ((urlpart = strtok(0, sep)) == 0)
continue;
if (strtok(0, sep) != 0)
continue;
#if DEBUG > 2
fprintf(stderr, "help_read_index: tag=\"%s\" urlpart=\"%s\"\n",
tag, urlpart);
#endif
if (hash == 0)
hash = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert(hash, g_strdup(tag), g_strdup(urlpart));
}
fclose(fp);
return hash;
}
static void
help_init_indexes(void)
{
int i;
char *file;
for (i = 0 ; help_locales[i] != 0 ; i++)
{
file = g_strconcat(HELPDIR "/", help_locales[i], "/index.dat", 0);
help_indexes[i] = help_read_index(file);
g_free(file);
}
}
static void
help_init(void)
{
if (help_initialised)
return;
help_initialised = TRUE;
help_init_locales();
help_init_indexes();
}
/* Look up the given tag and return a file:/ URL or NULL */
static char *
help_lookup(const char *tag)
{
#define URLPREFIX "file://"
#define URLPREFIXLEN (sizeof(URLPREFIX)-1)
char *url = 0;
int i;
help_init();
for (i = 0 ; help_locales[i] != 0 ; i++)
{
/* first try to lookup the index for this locale */
if (help_indexes[i] != 0)
{
char *urlpart;
char *filesep;
if ((urlpart = g_hash_table_lookup(help_indexes[i], tag)) != 0)
{
url = g_strconcat(URLPREFIX HELPDIR "/", help_locales[i], "/", urlpart, 0);
filesep = strrchr(url, '/');
filesep = strchr(filesep, '#');
if (filesep != 0)
*filesep = '\0';
if (file_exists(url+URLPREFIXLEN))
{
if (filesep != 0)
*filesep = '#';
break;
}
g_free(url);
url = 0;
}
}
/* not found in index, maybe there's a file of that name */
url = g_strconcat(URLPREFIX HELPDIR "/", help_locales[i], "/", tag, ".html", 0);
#if DEBUG > 2
fprintf(stderr, "help_lookup: trying \"%s\"\n", url);
#endif
if (file_exists(url+URLPREFIXLEN))
break;
g_free(url);
url = 0;
}
#if DEBUG > 2
fprintf(stderr, "help_lookup: \"%s\" -> \"%s\"\n", tag, url);
#endif
return url;
#undef URLPREFIX
#undef URLPREFIXLEN
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static TaskOps help_browser_ops =
{
0, /* start */
0, /* input */
0, /* reap */
0 /* destroy */
};
/*
* Possible browser commands are (where %u is the url):
* gnome-help-browser '%u'
* gnome-moz-remote --newwin '%u'
* netscape -remote 'openURL(%u)'
* xterm -e lynx '%u'
* ?? konqueror '%u'
* ?? opera %u
*/
static Task *
help_browser_task(const char *url)
{
const char *expands[256];
memset(expands, 0, sizeof(expands));
expands['u'] = url;
return task_create(
(Task *)g_new(Task, 1),
expand_string(prefs.prog_help_browser, expands),
/*environment*/0,
&help_browser_ops,
0);
}
static void
help_goto_url(const char *url)
{
task_spawn(help_browser_task(url));
}
static void
help_goto_tag(const char *tag)
{
char *url;
if ((url = help_lookup(tag)) != 0)
{
help_goto_url(url);
g_free(url);
}
}
void
help_goto_tag_cb(GtkWidget *w, gpointer data)
{
help_goto_tag((const char *)data);
}
void
help_goto_url_cb(GtkWidget *w, gpointer data)
{
help_goto_url((const char *)data);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
#include "help_cursor.xbm"
#include "help_cursor_mask.xbm"
void
help_on_cb(GtkWidget *w, void *user_data)
{
GdkEvent *event;
const char *tag;
static GdkCursor *help_cursor = 0;
if (help_cursor == 0)
{
GdkBitmap *source, *mask;
GdkColor fg, bg;
source = gdk_bitmap_create_from_data(
toplevel->window,
(char*)help_cursor_bits,
help_cursor_width,
help_cursor_height);
mask = gdk_bitmap_create_from_data(
toplevel->window,
(char*)help_cursor_mask_bits,
help_cursor_width,
help_cursor_height);
fg.red = 0; fg.green = 0; fg.blue = 0; /* black */
bg.red = 0xffff; bg.green = 0xffff; bg.blue = 0xffff; /* white */
help_cursor = gdk_cursor_new_from_pixmap(
source, mask,
&fg, &bg,
help_cursor_hot_x, help_cursor_hot_y);
/* TODO: free source, mask */
}
/*
* TODO: create a little toy window, pass it in as the 1st argument
* to gdk_pointer_grab(), add an event handler to it, and use the
* normal gtk main loop to wait for a button press event on it.
*/
gdk_pointer_grab(toplevel->window,
/*owner_events*/TRUE,
GDK_BUTTON_PRESS_MASK/*|GDK_BUTTON_RELEASE_MASK|GDK_POINTER_MOTION_MASK*/,
/*confine_to*/0,
help_cursor,
GDK_CURRENT_TIME);
#if DEBUG > 2
fprintf(stderr, "help_on_cb: about to get events\n");
#endif
for (;;)
{
if ((event = gdk_event_get()) == 0)
{
sleep(1);
continue;
}
#if DEBUG > 2
fprintf(stderr, "help_on_cb: event->type = %d\n", event->type);
#endif
if (event->type == GDK_BUTTON_PRESS)
{
#if DEBUG > 2
fprintf(stderr, "help_on_cb: Trying to find help...\n");
#endif
if ((w = gtk_get_event_widget(event)) != 0 &&
(tag = ui_get_help_tag(w)) != 0)
help_goto_tag(tag);
break;
}
else if (event->type == GDK_ENTER_NOTIFY ||
event->type == GDK_LEAVE_NOTIFY ||
event->type == GDK_EXPOSE)
{
/* pass these on to GTK so it can highlight buttons etc */
gtk_main_do_event(event);
}
/* TODO: do we need to free the event?? */
}
#if DEBUG > 2
fprintf(stderr, "help_on_cb: finished getting events\n");
#endif
gdk_pointer_ungrab(GDK_CURRENT_TIME);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*END*/
syntax highlighted by Code2HTML, v. 0.9.1