Initial import
This commit is contained in:
parent
293a073f86
commit
7cf72667e4
|
@ -0,0 +1,259 @@
|
|||
#include <glib-object.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
#include "gm-text-scroller.h"
|
||||
#include "../debug.h"
|
||||
#include "../gm-support.h"
|
||||
|
||||
#define GM_TEXT_SCROLLER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_TEXT_SCROLLER, GmTextScrollerPrivate))
|
||||
|
||||
struct _GmTextScrollerPrivate {
|
||||
GtkTextView *text_view;
|
||||
GtkTextBuffer *text_buffer;
|
||||
GtkScrolledWindow *scrolled_window;
|
||||
|
||||
gint character_height;
|
||||
gboolean end_scrolled;
|
||||
gint idle_handler;
|
||||
};
|
||||
|
||||
void on_gm_text_scroller_text_view_style_set(GtkTextView *view,
|
||||
GtkStyle *previous_style, GmTextScroller *scroller);
|
||||
void on_gm_text_scroller_text_buffer_changed(GtkTextBuffer *text_buffer,
|
||||
GmTextScroller *scroller);
|
||||
void on_gm_text_scroller_text_view_notify(GtkTextView *text_view, GParamSpec *arg1,
|
||||
GmTextScroller *scroller);
|
||||
void on_gm_text_scroller_text_view_destroy(GtkTextView *text_view,
|
||||
GmTextScroller *scroller);
|
||||
|
||||
/* Signals
|
||||
|
||||
enum {
|
||||
PROTO
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint gm_text_scroller_signals[NUM_SIGNALS] = {0};*/
|
||||
|
||||
G_DEFINE_TYPE(GmTextScroller, gm_text_scroller, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gm_text_scroller_finalize(GObject *object) {
|
||||
GmTextScroller *obj = GM_TEXT_SCROLLER(object);
|
||||
|
||||
if (obj->priv->text_buffer != NULL) {
|
||||
g_signal_handlers_disconnect_by_func(obj->priv->text_buffer,
|
||||
G_CALLBACK(on_gm_text_scroller_text_buffer_changed),
|
||||
obj);
|
||||
|
||||
g_object_unref(obj->priv->text_buffer);
|
||||
}
|
||||
|
||||
g_signal_handlers_disconnect_by_func(obj->priv->text_view,
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_notify), obj);
|
||||
g_signal_handlers_disconnect_by_func(obj->priv->text_view,
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_style_set), obj);
|
||||
g_signal_handlers_disconnect_by_func(obj->priv->text_view,
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_destroy), obj);
|
||||
|
||||
G_OBJECT_CLASS(gm_text_scroller_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
gm_text_scroller_class_init(GmTextScrollerClass *klass) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = gm_text_scroller_finalize;
|
||||
|
||||
/*gm_text_scroller_signals[PROTO] =
|
||||
g_signal_new("proto",
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET(GmTextScrollerClass, proto),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);*/
|
||||
|
||||
g_type_class_add_private(object_class, sizeof(GmTextScrollerPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gm_text_scroller_init(GmTextScroller *obj) {
|
||||
obj->priv = GM_TEXT_SCROLLER_GET_PRIVATE(obj);
|
||||
|
||||
obj->priv->character_height = 10;
|
||||
obj->priv->end_scrolled = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gm_text_scroller_update_text_buffer(GmTextScroller *scroller) {
|
||||
if (scroller->priv->text_buffer != NULL) {
|
||||
g_signal_handlers_disconnect_by_func(scroller->priv->text_buffer,
|
||||
G_CALLBACK(on_gm_text_scroller_text_buffer_changed),
|
||||
scroller);
|
||||
|
||||
g_object_unref(scroller->priv->text_buffer);
|
||||
}
|
||||
|
||||
scroller->priv->text_buffer =
|
||||
gtk_text_view_get_buffer(scroller->priv->text_view);
|
||||
|
||||
if (scroller->priv->text_buffer != NULL) {
|
||||
g_object_ref(scroller->priv->text_buffer);
|
||||
|
||||
g_signal_connect(scroller->priv->text_buffer, "changed",
|
||||
G_CALLBACK(on_gm_text_scroller_text_buffer_changed), scroller);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gm_text_scroller_scroll_end(GmTextScroller *scroller) {
|
||||
GtkTextMark *mark;
|
||||
GtkTextIter iter;
|
||||
|
||||
mark = gtk_text_buffer_get_mark(scroller->priv->text_buffer,
|
||||
"end-of-buffer");
|
||||
|
||||
if (mark == NULL) {
|
||||
gtk_text_buffer_get_end_iter(scroller->priv->text_buffer, &iter);
|
||||
mark = gtk_text_buffer_create_mark(scroller->priv->text_buffer,
|
||||
"end-of-buffer", &iter, FALSE);
|
||||
}
|
||||
|
||||
gtk_text_view_scroll_to_mark(scroller->priv->text_view, mark, 0.0,
|
||||
TRUE, 1.0, 1.0);
|
||||
}
|
||||
|
||||
void
|
||||
gm_text_scroller_scroll_begin(GmTextScroller *scroller) {
|
||||
GtkTextMark *mark;
|
||||
GtkTextIter iter;
|
||||
|
||||
mark = gtk_text_buffer_get_mark(scroller->priv->text_buffer,
|
||||
"begin-of-buffer");
|
||||
|
||||
if (mark == NULL) {
|
||||
gtk_text_buffer_get_start_iter(scroller->priv->text_buffer, &iter);
|
||||
mark = gtk_text_buffer_create_mark(scroller->priv->text_buffer,
|
||||
"begin-of-buffer", &iter, TRUE);
|
||||
}
|
||||
|
||||
gtk_text_view_scroll_to_mark(scroller->priv->text_view, mark, 0.0,
|
||||
TRUE, 0.0, 0.0);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gm_text_scroller_scroll_end_idle(GmTextScroller *scroller) {
|
||||
scroller->priv->idle_handler = 0;
|
||||
gm_text_scroller_scroll_end(scroller);
|
||||
scroller->priv->end_scrolled = FALSE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gm_text_scroller_prepare(GmTextScroller *scroller) {
|
||||
GtkAdjustment *ad = gtk_scrolled_window_get_vadjustment(
|
||||
scroller->priv->scrolled_window);
|
||||
|
||||
scroller->priv->end_scrolled = scroller->priv->end_scrolled ||
|
||||
((ad->page_size + ad->value) >= ad->upper -
|
||||
(double)(scroller->priv->character_height));
|
||||
|
||||
if (scroller->priv->idle_handler == 0 && scroller->priv->end_scrolled) {
|
||||
scroller->priv->idle_handler = g_idle_add((GSourceFunc)
|
||||
gm_text_scroller_scroll_end_idle, scroller);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gm_text_scroller_update_character_height(GmTextScroller *scroller) {
|
||||
GtkRcStyle *style = gtk_widget_get_modifier_style(GTK_WIDGET(
|
||||
scroller->priv->text_view));
|
||||
PangoContext *pc = gtk_widget_create_pango_context(GTK_WIDGET(
|
||||
scroller->priv->text_view));
|
||||
PangoLayout *pl;
|
||||
gint cwidth, cheight;
|
||||
|
||||
if (style->font_desc != NULL) {
|
||||
pango_context_set_font_description(pc, style->font_desc);
|
||||
pl = pango_layout_new(pc);
|
||||
|
||||
pango_layout_set_text(pl, "G", 1);
|
||||
pango_layout_get_pixel_size(pl, &(cwidth),
|
||||
&(cheight));
|
||||
|
||||
if (scroller->priv->character_height != cheight) {
|
||||
scroller->priv->character_height = cheight;
|
||||
}
|
||||
|
||||
g_object_unref(pl);
|
||||
}
|
||||
|
||||
g_object_unref(pc);
|
||||
}
|
||||
|
||||
GmTextScroller *
|
||||
gm_text_scroller_new(GtkTextView *text_view) {
|
||||
GmTextScroller *obj;
|
||||
GtkWidget *parent = gtk_widget_get_parent(GTK_WIDGET(text_view));
|
||||
|
||||
if (parent == NULL || !GTK_IS_SCROLLED_WINDOW(parent)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj = GM_TEXT_SCROLLER(g_object_new(GM_TYPE_TEXT_SCROLLER,
|
||||
NULL));
|
||||
|
||||
obj->priv->text_view = text_view;
|
||||
obj->priv->scrolled_window = GTK_SCROLLED_WINDOW(parent);
|
||||
|
||||
gm_text_scroller_update_text_buffer(obj);
|
||||
gm_text_scroller_update_character_height(obj);
|
||||
|
||||
g_signal_connect(text_view, "notify",
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_notify), obj);
|
||||
g_signal_connect(text_view, "style-set",
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_style_set), obj);
|
||||
g_signal_connect(text_view, "destroy",
|
||||
G_CALLBACK(on_gm_text_scroller_text_view_destroy), obj);
|
||||
|
||||
obj->priv->idle_handler = g_idle_add((GSourceFunc)
|
||||
gm_text_scroller_scroll_end_idle, obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Callbacks
|
||||
|
||||
void
|
||||
on_gm_text_scroller_text_view_notify(GtkTextView *text_view, GParamSpec *arg1,
|
||||
GmTextScroller *scroller) {
|
||||
if (strcmp(arg1->name, "buffer") == 0) {
|
||||
// Buffer changed
|
||||
gm_text_scroller_update_text_buffer(scroller);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_text_scroller_text_view_style_set(GtkTextView *view,
|
||||
GtkStyle *previous_style, GmTextScroller *scroller) {
|
||||
gm_text_scroller_update_character_height(scroller);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_text_scroller_text_buffer_changed(GtkTextBuffer *text_buffer,
|
||||
GmTextScroller *scroller) {
|
||||
// Changed...
|
||||
gm_text_scroller_prepare(scroller);
|
||||
}
|
||||
|
||||
void
|
||||
on_gm_text_scroller_text_view_destroy(GtkTextView *text_view,
|
||||
GmTextScroller *scroller) {
|
||||
// Remove ourselfs when the text view dies
|
||||
g_object_unref(scroller);
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef __GM_TEXT_SCROLLER_H__
|
||||
#define __GM_TEXT_SCROLLER_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define GM_TYPE_TEXT_SCROLLER (gm_text_scroller_get_type())
|
||||
#define GM_TEXT_SCROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_TEXT_SCROLLER, GmTextScroller))
|
||||
#define GM_TEXT_SCROLLER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_TEXT_SCROLLER, GmTextScroller const))
|
||||
#define GM_TEXT_SCROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_TEXT_SCROLLER, GmTextScrollerClass))
|
||||
#define GM_IS_TEXT_SCROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_TEXT_SCROLLER))
|
||||
#define GM_IS_TEXT_SCROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_TEXT_SCROLLER))
|
||||
#define GM_TEXT_SCROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_TEXT_SCROLLER, GmTextScrollerClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _GmTextScrollerPrivate GmTextScrollerPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _GmTextScroller GmTextScroller;
|
||||
|
||||
struct _GmTextScroller {
|
||||
GObject parent;
|
||||
|
||||
/*< private > */
|
||||
GmTextScrollerPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _GmTextScrollerClass GmTextScrollerClass;
|
||||
|
||||
struct _GmTextScrollerClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals
|
||||
void (* proto) (GmTextScroller *obj); */
|
||||
};
|
||||
|
||||
GType gm_text_scroller_get_type(void) G_GNUC_CONST;
|
||||
GmTextScroller *gm_text_scroller_new(GtkTextView *text_view);
|
||||
void gm_text_scroller_scroll_end(GmTextScroller *scroller);
|
||||
void gm_text_scroller_scroll_begin(GmTextScroller *scroller);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GM_TEXT_SCROLLER_H__ */
|
Reference in New Issue