* merge start of simple gtk+ ui for mu: 'mug'

This commit is contained in:
Dirk-Jan C. Binnema 2010-11-02 21:21:32 +02:00
parent 1d08c8df01
commit 70648b8bd5
11 changed files with 1082 additions and 3 deletions

View File

@ -16,7 +16,12 @@
include $(top_srcdir)/gtest.mk
if HAVE_GTK
SUBDIRS=man src mug contrib
else
SUBDIRS=man src contrib
endif
# so we can say 'make test'
check: test cleanupnote

View File

@ -116,6 +116,29 @@ AS_IF([test "x$have_gmime" = "xno"],[
])
])
# do we have gtk+ installed? if not, don't build 'mug'
PKG_CHECK_MODULES(GTK,gtk+-2.0,[have_gtk=yes],[have_gtk=no])
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)
AS_IF([test "x$have_gtk" = "xno"],[
AC_MSG_WARN([
*** gtk+-2.0 not found, mug will not be built
])
])
AM_CONDITIONAL(HAVE_GTK,test "x$have_gtk" = "xyes")
# do we have webkit/gtk installed? if not, don't try to use it for 'mug'
PKG_CHECK_MODULES(WEBKIT,webkit-1.0,[have_webkit=yes],[have_webkit=no])
AC_SUBST(WEBKIT_CFLAGS)
AC_SUBST(WEBKIT_LIBS)
AS_IF([test "x$have_webkit" = "xno"],[
AC_MSG_WARN([
*** webkit-1.0 not found, mug will not use webkit
])
])
AC_DEFINE(HAVE_WEBKIT,[1],[Whether we have Webkit/Gtk])
# xapian?
AC_CHECK_PROG(XAPIAN,xapian-config,xapian-config,no)
AM_CONDITIONAL(HAVE_XAPIAN,test "x$XAPIAN" != "xno")
@ -130,9 +153,7 @@ AS_IF([test "x$XAPIAN" = "xno"],[
XAPIAN_CXXFLAGS=`$XAPIAN --cxxflags`
XAPIAN_LIBS=`$XAPIAN --libs`
have_xapian="yes"
AC_DEFINE(HAVE_XAPIAN,[1],[Whether we have Xapian])
])
])
AC_SUBST(XAPIAN_CXXFLAGS)
AC_SUBST(XAPIAN_LIBS)
@ -140,6 +161,7 @@ AC_CONFIG_FILES([
Makefile
src/Makefile
src/tests/Makefile
mug/Makefile
man/Makefile
contrib/Makefile
])

51
mug/Makefile.am Normal file
View File

@ -0,0 +1,51 @@
## Copyright (C) 2008-2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
##
## 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
include $(top_srcdir)/gtest.mk
# enforce compiling this dir first before decending into tests/
SUBDIRS= .
#if HAVE_GTEST
#SUBDIRS += tests
#endif
INCLUDES=-I${top_srcdir}/src $(GTK_CFLAGS)
# don't use -Werror, as it might break on other compilers
# use -Wno-unused-parameters, because some callbacks may not
# really need all the params they get
AM_CFLAGS=-Wall -Wextra -Wno-unused-parameter -Wdeclaration-after-statement
AM_CXXFLAGS=-Wall -Wextra -Wno-unused-parameter
bin_PROGRAMS= \
mug
# note, mu.cc is only '.cc' and not '.c' because libmu must explicitly
# be linked as c++, not c.
mug_SOURCES= \
mug.cc \
mug-msg-list-view.c \
mug-msg-list-view.h \
mug-msg-view.h \
mug-msg-view.c \
mug-query-bar.h \
mug-query-bar.c
mug_LDADD= \
${top_srcdir}/src/libmu.la \
${GTK_LIBS}

18
mug/TODO Normal file
View File

@ -0,0 +1,18 @@
* todo for mug
** TODO column sizing
** TODO query in status bar
** TODO tool bar working
** TODO pretty-print addresses
** TODO pretty-print dates
** TODO up/down arrows => need msg-list-view support
** TODO unread mails => bold, important mails => red
** TODO detail info about current msg
** TODO guess maildir
** TODO properties dialog
** TODO bookmarks
** TODO icon / .desktop file
** TODO clear msg when starting new query

282
mug/mug-msg-list-view.c Normal file
View File

@ -0,0 +1,282 @@
/*
** Copyright (C) 2008-2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**
*/
#include "mug-msg-list-view.h"
#include "mu-query.h"
#include "mu-msg-str.h"
/* include other impl specific header files */
/* 'private'/'protected' functions */
static void mug_msg_list_view_class_init (MugMsgListViewClass *klass);
static void mug_msg_list_view_init (MugMsgListView *obj);
static void mug_msg_list_view_finalize (GObject *obj);
/* list my signals */
enum {
MUG_MSG_SELECTED,
LAST_SIGNAL
};
enum {
MUG_COL_DATE,
MUG_COL_FROM,
MUG_COL_TO,
MUG_COL_SUBJECT,
MUG_COL_PATH,
MUG_N_COLS
};
typedef struct _MugMsgListViewPrivate MugMsgListViewPrivate;
struct _MugMsgListViewPrivate {
GtkListStore *_store;
char *_xpath;
};
#define MUG_MSG_LIST_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
MUG_TYPE_MSG_LIST_VIEW, \
MugMsgListViewPrivate))
/* globals */
static GtkTreeViewClass *parent_class = NULL;
/* uncomment the following if you have defined any signals */
static guint signals[LAST_SIGNAL] = {0};
GType
mug_msg_list_view_get_type (void)
{
static GType my_type = 0;
if (!my_type) {
static const GTypeInfo my_info = {
sizeof(MugMsgListViewClass),
NULL, /* base init */
NULL, /* base finalize */
(GClassInitFunc) mug_msg_list_view_class_init,
NULL, /* class finalize */
NULL, /* class data */
sizeof(MugMsgListView),
0, /* n_preallocs, ignored since 2.10 */
(GInstanceInitFunc) mug_msg_list_view_init,
NULL
};
my_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
"MugMsgListView",
&my_info, 0);
}
return my_type;
}
static void
mug_msg_list_view_class_init (MugMsgListViewClass *klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass*) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = mug_msg_list_view_finalize;
g_type_class_add_private (gobject_class, sizeof(MugMsgListViewPrivate));
signals[MUG_MSG_SELECTED] =
g_signal_new ("msg-selected",
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET(MugMsgListViewClass, msg_selected),
NULL, NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
}
static void
on_cursor_changed (GtkTreeView *tview, MugMsgListView *lst)
{
GtkTreeSelection *sel;
GtkTreeIter iter;
MugMsgListViewPrivate *priv;
priv = MUG_MSG_LIST_VIEW_GET_PRIVATE(tview);
sel = gtk_tree_view_get_selection (tview);
if (!sel)
return; /* hmmm */
if (gtk_tree_selection_get_selected (sel, NULL, &iter)) {
char *path;
gtk_tree_model_get (GTK_TREE_MODEL(priv->_store), &iter,
MUG_COL_PATH, &path, -1);
g_signal_emit (G_OBJECT(lst),
signals[MUG_MSG_SELECTED], 0,
path);
g_free (path);
}
}
static GtkTreeViewColumn *
get_col (const char* label, int colidx)
{
GtkTreeViewColumn *col;
GtkCellRenderer *renderer;
renderer = gtk_cell_renderer_text_new ();
g_object_set (G_OBJECT(renderer),"ellipsize", PANGO_ELLIPSIZE_END, NULL);
col = gtk_tree_view_column_new_with_attributes (label, renderer, "text",
colidx, NULL);
g_object_set (G_OBJECT(col), "resizable", TRUE, NULL);
//g_object_unref (renderer);
return col;
}
static void
mug_msg_list_view_init (MugMsgListView *obj)
{
GtkTreeViewColumn *col;
MugMsgListViewPrivate *priv;
priv = MUG_MSG_LIST_VIEW_GET_PRIVATE(obj);
priv->_xpath = NULL;
priv->_store = gtk_list_store_new (MUG_N_COLS,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING);
gtk_tree_view_set_model (GTK_TREE_VIEW (obj),
GTK_TREE_MODEL(priv->_store));
gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(obj), TRUE);
gtk_tree_view_set_grid_lines (GTK_TREE_VIEW(obj),
GTK_TREE_VIEW_GRID_LINES_VERTICAL);
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(obj), TRUE);
col = get_col ("Date", MUG_COL_DATE);
gtk_tree_view_append_column (GTK_TREE_VIEW (obj), col);
col = get_col ("From", MUG_COL_FROM);
gtk_tree_view_append_column (GTK_TREE_VIEW (obj), col);
col = get_col ("To", MUG_COL_TO);
gtk_tree_view_append_column (GTK_TREE_VIEW (obj), col);
col = get_col ("Subject", MUG_COL_SUBJECT);
gtk_tree_view_append_column (GTK_TREE_VIEW (obj), col);
g_signal_connect (G_OBJECT(obj), "cursor-changed", G_CALLBACK(on_cursor_changed),
obj);
}
static void
mug_msg_list_view_finalize (GObject *obj)
{
MugMsgListViewPrivate *priv;
priv = MUG_MSG_LIST_VIEW_GET_PRIVATE(obj);
if (priv->_store)
g_object_unref (priv->_store);
g_free (priv->_xpath);
G_OBJECT_CLASS(parent_class)->finalize (obj);
}
GtkWidget*
mug_msg_list_view_new (const char *xpath)
{
GtkWidget *w;
MugMsgListViewPrivate *priv;
g_return_val_if_fail (xpath, NULL);
w = GTK_WIDGET(g_object_new(MUG_TYPE_MSG_LIST_VIEW, NULL));
priv = MUG_MSG_LIST_VIEW_GET_PRIVATE(w);
priv->_xpath = g_strdup (xpath);
return w;
}
static int
update_model (GtkListStore *store, const char *xpath, const char *query)
{
MuQuery *xapian;
MuMsgIter *iter;
int count;
xapian = mu_query_new (xpath);
if (!xapian) {
g_printerr ("Failed to create a Xapian query\n");
return -1;
}
iter = mu_query_run (xapian, query, NULL, TRUE, 0);
if (!iter) {
g_warning ("error: running query failed\n");
mu_query_destroy (xapian);
return -1;
}
for (count = 0; !mu_msg_iter_is_done (iter);
mu_msg_iter_next (iter), ++count) {
GtkTreeIter treeiter;
const gchar *date, *from, *subject, *path, *to;
date = mu_msg_str_date_s (mu_msg_iter_get_date (iter));
from = mu_msg_iter_get_from(iter);
to = mu_msg_iter_get_to (iter);
subject = mu_msg_iter_get_subject (iter);
path = mu_msg_iter_get_path (iter);
gtk_list_store_append (store, &treeiter);
gtk_list_store_set (store, &treeiter,
MUG_COL_DATE, date,
MUG_COL_FROM, from,
MUG_COL_TO, to,
MUG_COL_SUBJECT, subject,
MUG_COL_PATH, path,
-1);
}
mu_query_destroy (xapian);
return count;
}
int
mug_msg_list_view_query (MugMsgListView *self, const char *query)
{
MugMsgListViewPrivate *priv;
g_return_val_if_fail (MUG_IS_MSG_LIST_VIEW(self), FALSE);
priv = MUG_MSG_LIST_VIEW_GET_PRIVATE(self);
gtk_list_store_clear (priv->_store);
if (!query)
return TRUE;
return update_model (priv->_store, priv->_xpath, query);
}

62
mug/mug-msg-list-view.h Normal file
View File

@ -0,0 +1,62 @@
/*
** Copyright (C) 2008-2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**
*/
#ifndef __MUG_MSG_LIST_VIEW_H__
#define __MUG_MSG_LIST_VIEW_H__
#include <gtk/gtk.h>
/* other include files */
G_BEGIN_DECLS
/* convenience macros */
#define MUG_TYPE_MSG_LIST_VIEW (mug_msg_list_view_get_type())
#define MUG_MSG_LIST_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),MUG_TYPE_MSG_LIST_VIEW,MugMsgListView))
#define MUG_MSG_LIST_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),MUG_TYPE_MSG_LIST_VIEW,MugMsgListViewClass))
#define MUG_IS_MSG_LIST_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),MUG_TYPE_MSG_LIST_VIEW))
#define MUG_IS_MSG_LIST_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),MUG_TYPE_MSG_LIST_VIEW))
#define MUG_MSG_LIST_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),MUG_TYPE_MSG_LIST_VIEW,MugMsgListViewClass))
typedef struct _MugMsgListView MugMsgListView;
typedef struct _MugMsgListViewClass MugMsgListViewClass;
struct _MugMsgListView {
GtkTreeView parent;
/* insert public members, if any */
};
struct _MugMsgListViewClass {
GtkTreeViewClass parent_class;
/* insert signal callback declarations, e.g. */
void (* msg_selected) (MugMsgListView* obj, const char* msgpath);
};
/* member functions */
GType mug_msg_list_view_get_type (void) G_GNUC_CONST;
/* parameter-less _new function (constructor) */
/* if this is a kind of GtkWidget, it should probably return at GtkWidget* */
GtkWidget* mug_msg_list_view_new (const char *xpath);
int mug_msg_list_view_query (MugMsgListView *self, const char *query);
G_END_DECLS
#endif /* __MUG_MSG_LIST_VIEW_H__ */

144
mug/mug-msg-view.c Normal file
View File

@ -0,0 +1,144 @@
/*
** Copyright (C) 2008-2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**
*/
#include "mug-msg-view.h"
#include "mu-msg.h"
/* 'private'/'protected' functions */
static void mug_msg_view_class_init (MugMsgViewClass *klass);
static void mug_msg_view_init (MugMsgView *obj);
static void mug_msg_view_finalize (GObject *obj);
/* list my signals */
enum {
/* MY_SIGNAL_1, */
/* MY_SIGNAL_2, */
LAST_SIGNAL
};
typedef struct _MugMsgViewPrivate MugMsgViewPrivate;
struct _MugMsgViewPrivate {
GtkWidget *_view;
};
#define MUG_MSG_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
MUG_TYPE_MSG_VIEW, MugMsgViewPrivate))
/* globals */
static GtkVBoxClass *parent_class = NULL;
/* uncomment the following if you have defined any signals */
/* static guint signals[LAST_SIGNAL] = {0}; */
GType
mug_msg_view_get_type (void)
{
static GType my_type = 0;
if (!my_type) {
static const GTypeInfo my_info = {
sizeof(MugMsgViewClass),
NULL, /* base init */
NULL, /* base finalize */
(GClassInitFunc) mug_msg_view_class_init,
NULL, /* class finalize */
NULL, /* class data */
sizeof(MugMsgView),
0, /* n_preallocs, ignored since 2.10 */
(GInstanceInitFunc) mug_msg_view_init,
NULL
};
my_type = g_type_register_static (GTK_TYPE_VBOX,
"MugMsgView",
&my_info, 0);
}
return my_type;
}
static void
mug_msg_view_class_init (MugMsgViewClass *klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass*) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = mug_msg_view_finalize;
g_type_class_add_private (gobject_class, sizeof(MugMsgViewPrivate));
/* signal definitions go here, e.g.: */
/* signals[MY_SIGNAL_1] = */
/* g_signal_new ("my_signal_1",....); */
/* signals[MY_SIGNAL_2] = */
/* g_signal_new ("my_signal_2",....); */
/* etc. */
}
static void
mug_msg_view_init (MugMsgView *obj)
{
MugMsgViewPrivate *priv;
priv = MUG_MSG_VIEW_GET_PRIVATE(obj);
priv->_view = gtk_text_view_new ();
gtk_text_view_set_editable (GTK_TEXT_VIEW(priv->_view), FALSE);
gtk_text_view_set_left_margin (GTK_TEXT_VIEW(priv->_view), 10);
gtk_text_view_set_right_margin (GTK_TEXT_VIEW(priv->_view), 10);
gtk_box_pack_start (GTK_BOX(obj), priv->_view, TRUE, TRUE, 0);
}
static void
mug_msg_view_finalize (GObject *obj)
{
/* free/unref instance resources here */
G_OBJECT_CLASS(parent_class)->finalize (obj);
}
GtkWidget*
mug_msg_view_new (void)
{
return GTK_WIDGET(g_object_new(MUG_TYPE_MSG_VIEW, NULL));
}
gboolean
mug_msg_view_set_msg (MugMsgView *self, const char* msgpath)
{
MugMsgViewPrivate *priv;
MuMsg* msg;
const char *txt;
GtkTextBuffer *buf;
g_return_val_if_fail (MUG_IS_MSG_VIEW(self), FALSE);
g_return_val_if_fail (msgpath, FALSE);
priv = MUG_MSG_VIEW_GET_PRIVATE(self);
msg = mu_msg_new (msgpath, NULL);
if (!msg)
return FALSE;
txt = mu_msg_get_body_text (msg);
buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(priv->_view));
gtk_text_buffer_set_text (buf, txt ? txt : "", -1);
return TRUE;
}

62
mug/mug-msg-view.h Normal file
View File

@ -0,0 +1,62 @@
/*
** Copyright (C) 2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**
*/
#ifndef __MUG_MSG_VIEW_H__
#define __MUG_MSG_VIEW_H__
#include <gtk/gtk.h>
/* other include files */
G_BEGIN_DECLS
/* convenience macros */
#define MUG_TYPE_MSG_VIEW (mug_msg_view_get_type())
#define MUG_MSG_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),MUG_TYPE_MSG_VIEW,MugMsgView))
#define MUG_MSG_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),MUG_TYPE_MSG_VIEW,MugMsgViewClass))
#define MUG_IS_MSG_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),MUG_TYPE_MSG_VIEW))
#define MUG_IS_MSG_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),MUG_TYPE_MSG_VIEW))
#define MUG_MSG_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),MUG_TYPE_MSG_VIEW,MugMsgViewClass))
typedef struct _MugMsgView MugMsgView;
typedef struct _MugMsgViewClass MugMsgViewClass;
struct _MugMsgView {
GtkVBox parent;
/* insert public members, if any */
};
struct _MugMsgViewClass {
GtkVBoxClass parent_class;
/* insert signal callback declarations, e.g. */
/* void (* my_event) (MugMsg* obj); */
};
/* member functions */
GType mug_msg_view_get_type (void) G_GNUC_CONST;
/* parameter-less _new function (constructor) */
/* if this is a kind of GtkWidget, it should probably return at GtkWidget* */
GtkWidget* mug_msg_view_new (void);
gboolean mug_msg_view_set_msg (MugMsgView *self, const char* msgpath);
G_END_DECLS
#endif /* __MUG_MSG_VIEW_H__ */

120
mug/mug-query-bar.c Normal file
View File

@ -0,0 +1,120 @@
/* mug-query-bar.c */
/* insert (c)/licensing information) */
#include "mug-query-bar.h"
/* include other impl specific header files */
/* 'private'/'protected' functions */
static void mug_query_bar_class_init (MugQueryBarClass *klass);
static void mug_query_bar_init (MugQueryBar *obj);
static void mug_query_bar_finalize (GObject *obj);
/* list my signals */
enum {
MUG_QUERY_CHANGED,
LAST_SIGNAL
};
typedef struct _MugQueryBarPrivate MugQueryBarPrivate;
struct _MugQueryBarPrivate {
GtkWidget *_entry;
};
#define MUG_QUERY_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
MUG_TYPE_QUERY_BAR, \
MugQueryBarPrivate))
/* globals */
static GtkContainerClass *parent_class = NULL;
static guint signals[LAST_SIGNAL] = {0};
GType
mug_query_bar_get_type (void)
{
static GType my_type = 0;
if (!my_type) {
static const GTypeInfo my_info = {
sizeof(MugQueryBarClass),
NULL, /* base init */
NULL, /* base finalize */
(GClassInitFunc) mug_query_bar_class_init,
NULL, /* class finalize */
NULL, /* class data */
sizeof(MugQueryBar),
0, /* n_preallocs, ignored since 2.10 */
(GInstanceInitFunc) mug_query_bar_init,
NULL
};
my_type = g_type_register_static (GTK_TYPE_HBOX,
"MugQueryBar",
&my_info, 0);
}
return my_type;
}
static void
mug_query_bar_class_init (MugQueryBarClass *klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass*) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = mug_query_bar_finalize;
g_type_class_add_private (gobject_class, sizeof(MugQueryBarPrivate));
/* signal definitions go here, e.g.: */
signals[MUG_QUERY_CHANGED] =
g_signal_new ("query_changed",
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET(MugQueryBarClass, query_changed),
NULL, NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
}
static void
on_entry_activated (GtkEntry *w, MugQueryBar *bar)
{
MugQueryBarPrivate *priv;
priv = MUG_QUERY_BAR_GET_PRIVATE(bar);
g_signal_emit (G_OBJECT(bar), signals[MUG_QUERY_CHANGED], 0,
gtk_entry_get_text(w));
}
static void
mug_query_bar_init (MugQueryBar *obj)
{
MugQueryBarPrivate *priv;
priv = MUG_QUERY_BAR_GET_PRIVATE(obj);
priv->_entry = gtk_entry_new ();
/* gtk_entry_set_max_length (GTK_ENTRY(priv->_entry), 32); */
g_signal_connect (priv->_entry, "activate", G_CALLBACK(on_entry_activated),
obj);
gtk_box_pack_start (GTK_BOX(obj), priv->_entry, TRUE, TRUE, 0);
}
static void
mug_query_bar_finalize (GObject *obj)
{
/* free/unref instance resources here */
G_OBJECT_CLASS(parent_class)->finalize (obj);
}
GtkWidget*
mug_query_bar_new (void)
{
return GTK_WIDGET(g_object_new(MUG_TYPE_QUERY_BAR, NULL));
}
/* following: other function implementations */
/* such as mug_query_bar_do_something, or mug_query_bar_has_foo */

45
mug/mug-query-bar.h Normal file
View File

@ -0,0 +1,45 @@
/* mug-query-bar.h */
/* insert (c)/licensing information) */
#ifndef __MUG_QUERY_BAR_H__
#define __MUG_QUERY_BAR_H__
#include <gtk/gtk.h>
/* other include files */
G_BEGIN_DECLS
/* convenience macros */
#define MUG_TYPE_QUERY_BAR (mug_query_bar_get_type())
#define MUG_QUERY_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),MUG_TYPE_QUERY_BAR,MugQueryBar))
#define MUG_QUERY_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),MUG_TYPE_QUERY_BAR,MugQueryBarClass))
#define MUG_IS_QUERY_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),MUG_TYPE_QUERY_BAR))
#define MUG_IS_QUERY_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),MUG_TYPE_QUERY_BAR))
#define MUG_QUERY_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),MUG_TYPE_QUERY_BAR,MugQueryBarClass))
typedef struct _MugQueryBar MugQueryBar;
typedef struct _MugQueryBarClass MugQueryBarClass;
struct _MugQueryBar {
GtkHBox parent;
/* insert public members, if any */
};
struct _MugQueryBarClass {
GtkHBoxClass parent_class;
/* insert signal callback declarations, e.g. */
void (* query_changed) (MugQueryBar* obj, const char *query);
};
/* member functions */
GType mug_query_bar_get_type (void) G_GNUC_CONST;
/* parameter-less _new function (constructor) */
/* if this is a kind of GtkWidget, it should probably return at GtkWidget* */
GtkWidget* mug_query_bar_new (void);
G_END_DECLS
#endif /* __MUG_QUERY_BAR_H__ */

268
mug/mug.cc Normal file
View File

@ -0,0 +1,268 @@
/*
** Copyright (C) 2008-2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <gtk/gtk.h>
#include "mu-config.h"
#include "mu-log.h"
#include "mu-util.h"
#include "mug-msg-list-view.h"
#include "mug-query-bar.h"
#include "mug-msg-view.h"
struct _MugData {
GtkWidget *statusbar;
GtkWidget *mlist;
GtkWidget *toolbar;
GtkWidget *msg;
};
typedef struct _MugData MugData;
static GtkWidget*
mug_menu (void)
{
GtkWidget *menu;
menu = gtk_menu_bar_new ();
return menu;
}
enum _ToolAction {
ACTION_PREV_MSG = 1,
ACTION_NEXT_MSG,
ACTION_SHOW_PREFS,
ACTION_DO_QUIT
};
typedef enum _ToolAction ToolAction;
static void
on_tool_button_clicked (GtkToolButton *btn, MugData *data)
{
ToolAction action;
action = (ToolAction)GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(btn), "action"));
switch (action) {
case ACTION_DO_QUIT:
gtk_main_quit();
break;
default:
g_print ("%u\n", action);
}
}
static GtkWidget*
mug_toolbar (MugData *mugdata)
{
GtkWidget *toolbar;
int i;
struct {
const char* stock_id;
ToolAction action;
} tools[] = {
{GTK_STOCK_GO_UP, ACTION_PREV_MSG},
{GTK_STOCK_GO_DOWN, ACTION_NEXT_MSG},
{GTK_STOCK_PREFERENCES, ACTION_SHOW_PREFS},
{GTK_STOCK_QUIT, ACTION_DO_QUIT}
};
for (toolbar = gtk_toolbar_new(), i = 0; i != G_N_ELEMENTS(tools); ++i) {
GtkToolItem *btn;
btn = gtk_tool_button_new_from_stock (tools[i].stock_id);
g_object_set_data (G_OBJECT(btn), "action", GUINT_TO_POINTER(tools[i].action));
g_signal_connect (G_OBJECT(btn), "clicked",
G_CALLBACK(on_tool_button_clicked),
mugdata);
gtk_toolbar_insert (GTK_TOOLBAR(toolbar), btn, i);
}
return toolbar;
}
static GtkWidget*
mug_statusbar (void)
{
GtkWidget *statusbar;
statusbar = gtk_statusbar_new ();
return statusbar;
}
static void
on_query_changed (MugQueryBar *bar, const char* query, MugData *mugdata)
{
int count;
count = mug_msg_list_view_query (MUG_MSG_LIST_VIEW(mugdata->mlist),
query);
if (count >= 0) {
gchar *msg = g_strdup_printf ("%d message%s found", count,
count > 1 ? "s" : "");
gtk_statusbar_push (GTK_STATUSBAR(mugdata->statusbar), 0, msg);
g_free (msg);
}
}
static void
on_msg_selected (MugMsgListView *mlist, const char* mpath, MugData *mugdata)
{
// g_warning ("msg selected: %s", mpath);
mug_msg_view_set_msg (MUG_MSG_VIEW(mugdata->msg), mpath);
}
static GtkWidget*
mug_querybar (void)
{
GtkWidget *querybar;
querybar = mug_query_bar_new ();
return querybar;
}
#if 0
static GtkWidget*
mug_shortcuts (void)
{
GtkWidget *shortcuts;
shortcuts = gtk_vbutton_box_new ();
gtk_box_pack_start (GTK_BOX(shortcuts),
gtk_button_new_with_label ("Inbox"), FALSE, FALSE, 2);
gtk_box_pack_start (GTK_BOX(shortcuts),
gtk_button_new_with_label ("Archive"), FALSE, FALSE, 2);
gtk_box_pack_start (GTK_BOX(shortcuts),
gtk_button_new_with_label ("Sent"), FALSE, FALSE, 2);
gtk_button_box_set_layout (GTK_BUTTON_BOX(shortcuts), GTK_BUTTONBOX_START);
return shortcuts;
}
#endif
static GtkWidget*
mug_query_area (MugData *mugdata)
{
GtkWidget *queryarea;
GtkWidget *paned, *querybar;
GtkWidget *scrolled;
queryarea = gtk_vbox_new (FALSE, 2);
paned = gtk_vpaned_new ();
mugdata->mlist = mug_msg_list_view_new("/home/dbinnema/.mu/xapian/");
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER(scrolled), mugdata->mlist);
gtk_paned_add1 (GTK_PANED (paned), scrolled);
mugdata->msg = mug_msg_view_new ();
g_signal_connect (G_OBJECT(mugdata->mlist), "msg-selected",
G_CALLBACK(on_msg_selected), mugdata);
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled),
mugdata->msg);
gtk_paned_add2 (GTK_PANED (paned), scrolled);
querybar = mug_querybar();
g_signal_connect (G_OBJECT(querybar), "query_changed",
G_CALLBACK(on_query_changed),
mugdata);
gtk_box_pack_start (GTK_BOX(queryarea),
querybar, FALSE, FALSE, 2);
gtk_box_pack_start (GTK_BOX(queryarea),
paned, TRUE, TRUE, 2);
return queryarea;
}
static GtkWidget*
mug_main_area (MugData *mugdata)
{
GtkWidget *mainarea;
mainarea = gtk_hpaned_new ();
//gtk_paned_add1 (GTK_PANED (mainarea), mug_shortcuts());
gtk_paned_add2 (GTK_PANED (mainarea), mug_query_area (mugdata));
return mainarea;
}
GtkWidget*
mug_shell (MugData *mugdata)
{
GtkWidget *win, *vbox;
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW(win), "mu");
vbox = gtk_vbox_new (FALSE, 2);
gtk_box_pack_start (GTK_BOX(vbox), mug_menu(), FALSE, FALSE, 2);
mugdata->toolbar = mug_toolbar(mugdata);
gtk_box_pack_start (GTK_BOX(vbox), mugdata->toolbar, FALSE, FALSE, 2);
gtk_box_pack_start (GTK_BOX(vbox), mug_main_area(mugdata), TRUE, TRUE, 2);
mugdata->statusbar = mug_statusbar();
gtk_box_pack_start (GTK_BOX(vbox), mugdata->statusbar, FALSE, FALSE, 2);
gtk_container_add (GTK_CONTAINER(win), vbox);
gtk_widget_show_all (vbox);
gtk_window_set_default_size (GTK_WINDOW(win), 500, 500);
gtk_window_set_resizable (GTK_WINDOW(win), TRUE);
return win;
}
int
main (int argc, char *argv[])
{
MugData mugdata;
GtkWidget *mugshell;
gtk_init (&argc, &argv);
mugshell = mug_shell (&mugdata);
g_signal_connect(G_OBJECT(mugshell), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show (mugshell);
gtk_main ();
return 0;
}