diff options
| -rw-r--r-- | README.adoc | 2 | ||||
| -rw-r--r-- | src/sdgui.c | 11 | ||||
| -rw-r--r-- | src/stardict-view.c | 441 | 
3 files changed, 329 insertions, 125 deletions
| diff --git a/README.adoc b/README.adoc index d5bee2c..9e95237 100644 --- a/README.adoc +++ b/README.adoc @@ -96,7 +96,7 @@ should be addressed before including the software in regular Linux and/or  BSD distributions:   - The tab bar doesn't handle overflows well in the TUI. - - The GUI has a few usability issues, and is awkward to configure. + - The GUI is awkward to configure.   - Lacking configuration, standard StarDict locations should be scanned.  Given all issues with the file format, it might be better to start anew. diff --git a/src/sdgui.c b/src/sdgui.c index 457e72e..72fdaac 100644 --- a/src/sdgui.c +++ b/src/sdgui.c @@ -128,6 +128,15 @@ on_changed (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gpointer data)  }  static void +on_send (G_GNUC_UNUSED StardictView *view, +	const char *word, G_GNUC_UNUSED gpointer data) +{ +	GtkEntryBuffer *buf = gtk_entry_get_buffer (GTK_ENTRY (g.entry)); +	gtk_entry_buffer_set_text (buf, word, -1); +	gtk_editable_select_region (GTK_EDITABLE (g.entry), 0, -1); +} + +static void  on_selection_received (G_GNUC_UNUSED GtkClipboard *clipboard, const gchar *text,  	G_GNUC_UNUSED gpointer data)  { @@ -529,6 +538,8 @@ main (int argc, char *argv[])  	gtk_drag_dest_add_uri_targets (g.view);  	g_signal_connect (g.view, "drag-data-received",  		G_CALLBACK (on_drag_data_received), NULL); +	g_signal_connect (g.view, "send", +		G_CALLBACK (on_send), NULL);  	gtk_widget_show_all (g.window);  	gtk_main (); diff --git a/src/stardict-view.c b/src/stardict-view.c index d073b16..056c240 100644 --- a/src/stardict-view.c +++ b/src/stardict-view.c @@ -149,15 +149,51 @@ struct view_entry_render_ctx  	PangoLayout *selection_layout;  	int selection_begin;  	int selection_end; +	PangoLayout *hover_layout; +	int hover_begin; +	int hover_end;  }; +static PangoLayout * +view_entry_adjust_layout (ViewEntryRenderCtx *ctx, PangoLayout *layout) +{ +	if (layout != ctx->hover_layout) +		return g_object_ref (layout); + +	layout = pango_layout_copy (layout); +	PangoAttrList *attrs = pango_layout_get_attributes (layout); +	attrs = attrs +		? pango_attr_list_copy (attrs) +		: pango_attr_list_new (); + +	PangoAttribute *u = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); +	u->start_index = ctx->hover_begin; +	u->end_index = ctx->hover_end; +	pango_attr_list_change (attrs, u); + +	PangoAttribute *uc = pango_attr_underline_color_new (0, 0, 0xffff); +	uc->start_index = ctx->hover_begin; +	uc->end_index = ctx->hover_end; +	pango_attr_list_change (attrs, uc); + +	PangoAttribute *c = pango_attr_foreground_new (0, 0, 0xffff); +	c->start_index = ctx->hover_begin; +	c->end_index = ctx->hover_end; +	pango_attr_list_change (attrs, c); + +	pango_layout_set_attributes (layout, attrs); +	pango_attr_list_unref (attrs); +	return layout; +} +  static void  view_entry_render (ViewEntryRenderCtx *ctx, gdouble x, gdouble y,  	PangoLayout *layout)  { -	gtk_render_layout (ctx->style, ctx->cr, x, y, layout); +	PangoLayout *adjusted = view_entry_adjust_layout (ctx, layout); +	gtk_render_layout (ctx->style, ctx->cr, x, y, adjusted);  	if (layout != ctx->selection_layout) -		return; +		goto out;  	gtk_style_context_save (ctx->style);  	gtk_style_context_set_state (ctx->style, GTK_STATE_FLAG_SELECTED); @@ -166,16 +202,18 @@ view_entry_render (ViewEntryRenderCtx *ctx, gdouble x, gdouble y,  	int ranges[2] = { MIN (ctx->selection_begin, ctx->selection_end),  		MAX (ctx->selection_begin, ctx->selection_end) };  	cairo_region_t *region -		= gdk_pango_layout_get_clip_region (layout, x, y, ranges, 1); +		= gdk_pango_layout_get_clip_region (adjusted, x, y, ranges, 1);  	gdk_cairo_region (ctx->cr, region);  	cairo_clip (ctx->cr);  	cairo_region_destroy (region);  	gtk_render_background (ctx->style, ctx->cr, 0, 0, ctx->width, ctx->height); -	gtk_render_layout (ctx->style, ctx->cr, x, y, layout); +	gtk_render_layout (ctx->style, ctx->cr, x, y, adjusted);  	cairo_restore (ctx->cr);  	gtk_style_context_restore (ctx->style); +out: +	g_object_unref (adjusted);  }  static gint @@ -272,6 +310,10 @@ struct _StardictView  	GWeakRef selection;                 ///< Selected PangoLayout, if any  	int selection_begin;                ///< Start index within `selection`  	int selection_end;                  ///< End index within `selection` + +	GWeakRef hover;                     ///< Hovered PangoLayout, if any +	int hover_begin;                    ///< Word start index within `hover` +	int hover_end;                      ///< Word end index within `hover`  };  static ViewEntry * @@ -284,6 +326,23 @@ make_entry (StardictView *self, StardictIterator *iterator)  }  static void +reset_hover (StardictView *self) +{ +	GtkWidget *widget = GTK_WIDGET (self); +	PangoLayout *hover = g_weak_ref_get (&self->hover); +	if (hover) +	{ +		g_object_unref (hover); +		g_weak_ref_set (&self->hover, NULL); +		self->hover_begin = self->hover_end = -1; +		gtk_widget_queue_draw (widget); +	} + +	if (gtk_widget_get_realized (widget)) +		gdk_window_set_cursor (gtk_widget_get_window (widget), NULL); +} + +static void  adjust_for_height (StardictView *self)  {  	GtkWidget *widget = GTK_WIDGET (self); @@ -314,15 +373,16 @@ adjust_for_height (StardictView *self)  	}  	g_object_unref (iterator); -	self->entries = g_list_concat (self->entries, g_list_reverse (append)); -	gtk_widget_queue_draw (widget); -  	// Also handling this for adjust_for_offset(), which calls this.  	PangoLayout *selection = g_weak_ref_get (&self->selection);  	if (selection)  		g_object_unref (selection);  	else  		self->selection_begin = self->selection_end = -1; + +	reset_hover (self); +	self->entries = g_list_concat (self->entries, g_list_reverse (append)); +	gtk_widget_queue_draw (widget);  }  static void @@ -378,6 +438,7 @@ reload (StardictView *self)  	// For consistency, and the check in make_context_menu()  	self->selection_begin = self->selection_end = -1; +	reset_hover (self);  	if (gtk_widget_get_realized (widget) && self->dict)  		adjust_for_height (self); @@ -393,10 +454,133 @@ natural_row_size (GtkWidget *widget)  	return height;  } +// --- Figuring out where stuff is---------------------------------------------- + +/// Figure out which layout is at given widget coordinates, and translate them. +static PangoLayout * +layout_at (StardictView *self, int *x, int *y) +{ +	GtkWidget *widget = GTK_WIDGET (self); +	int width = gtk_widget_get_allocated_width (widget); + +	// The algorithm here is a simplification of stardict_view_draw(). +	GtkStyleContext *style = gtk_widget_get_style_context (widget); +	GtkBorder padding = view_entry_get_padding (style); +	gint offset = -self->top_offset; +	for (GList *iter = self->entries; iter; iter = iter->next) +	{ +		ViewEntry *ve = iter->data; +		if (G_UNLIKELY (*y < offset)) +			break; + +		gint top_y = offset, word_y = 0, defn_y = 0; +		offset += view_entry_height (ve, &word_y, &defn_y); +		if (*y >= offset) +			continue; + +		if (*x >= width / 2) +		{ +			*x -= width / 2 + padding.left; +			*y -= top_y + defn_y; +			return ve->definition_layout; +		} +		else +		{ +			*x -= padding.left; +			*y -= top_y + word_y; +			return ve->word_layout; +		} +	} +	return NULL; +} + +/// Figure out a layout's coordinates. +static gboolean +layout_coords (StardictView *self, PangoLayout *layout, int *x, int *y) +{ +	GtkWidget *widget = GTK_WIDGET (self); +	int width = gtk_widget_get_allocated_width (widget); + +	// The algorithm here is a simplification of stardict_view_draw(). +	GtkStyleContext *style = gtk_widget_get_style_context (widget); +	GtkBorder padding = view_entry_get_padding (style); +	gint offset = -self->top_offset; +	for (GList *iter = self->entries; iter; iter = iter->next) +	{ +		ViewEntry *ve = iter->data; +		gint top_y = offset, word_y = 0, defn_y = 0; +		offset += view_entry_height (ve, &word_y, &defn_y); + +		if (layout == ve->definition_layout) +		{ +			*x = width / 2 + padding.left; +			*y = top_y + defn_y; +			return TRUE; +		} +		if (layout == ve->word_layout) +		{ +			*x = padding.left; +			*y = top_y + word_y; +			return TRUE; +		} +	} +	return FALSE; +} + +static int +layout_index_at (PangoLayout *layout, int x, int y) +{ +	int index = 0, trailing = 0; +	(void) pango_layout_xy_to_index (layout, +		x * PANGO_SCALE, +		y * PANGO_SCALE, +		&index, +		&trailing); + +	const char *text = pango_layout_get_text (layout) + index; +	while (trailing--) +	{ +		int len = g_utf8_next_char (text) - text; +		text += len; +		index += len; +	} +	return index; +} + +static PangoLayout * +locate_word_at (StardictView *self, int x, int y, int *beginpos, int *endpos) +{ +	*beginpos = -1; +	*endpos = -1; +	PangoLayout *layout = layout_at (self, &x, &y); +	if (!layout) +		return NULL; + +	const char *text = pango_layout_get_text (layout), *p = NULL; +	const char *begin = text + layout_index_at (layout, x, y), *end = begin; +	while ((p = g_utf8_find_prev_char (text, begin)) +		&& !g_unichar_isspace (g_utf8_get_char (p))) +		begin = p; +	gunichar c; +	while ((c = g_utf8_get_char (end)) && !g_unichar_isspace (c)) +		end = g_utf8_next_char (end); + +	*beginpos = begin - text; +	*endpos = end - text; +	return layout; +} +  // --- Boilerplate -------------------------------------------------------------  G_DEFINE_TYPE (StardictView, stardict_view, GTK_TYPE_WIDGET) +enum { +	SEND, +	LAST_SIGNAL, +}; + +static guint view_signals[LAST_SIGNAL]; +  static void  stardict_view_finalize (GObject *gobject)  { @@ -454,11 +638,11 @@ stardict_view_realize (GtkWidget *widget)  		.wclass      = GDK_INPUT_OUTPUT,  		.visual      = gtk_widget_get_visual (widget),  		.event_mask  = gtk_widget_get_events (widget) | GDK_SCROLL_MASK -			| GDK_SMOOTH_SCROLL_MASK | GDK_BUTTON_PRESS_MASK, +			| GDK_SMOOTH_SCROLL_MASK | GDK_BUTTON_PRESS_MASK +			| GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK,  	};  	// We need this window to receive input events at all. -	// TODO: see if we don't want GDK_WA_CURSOR for setting a text cursor  	GdkWindow *window = gdk_window_new (gtk_widget_get_parent_window (widget),  		&attributes, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL); @@ -468,6 +652,61 @@ stardict_view_realize (GtkWidget *widget)  	gtk_widget_set_realized (widget, TRUE);  } +static void +reset_hover_for_event (StardictView *self, guint state, int x, int y) +{ +	reset_hover (self); +	if ((state &= gtk_accelerator_get_default_mod_mask ()) != GDK_CONTROL_MASK) +		return; + +	g_weak_ref_set (&self->hover, +		locate_word_at (self, x, y, &self->hover_begin, &self->hover_end)); +	gtk_widget_queue_draw (GTK_WIDGET (self)); + +	GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (self)); +	GdkCursor *cursor = gdk_cursor_new_from_name +		(gdk_window_get_display (window), "pointer"); +	gdk_window_set_cursor (window, cursor); +	g_object_unref (cursor); +} + +static void +on_keymap_state_changed (G_GNUC_UNUSED GdkKeymap *keymap, StardictView *self) +{ +	GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (self)); +	GdkSeat *seat = gdk_display_get_default_seat (display); +	GdkDevice *pointer = gdk_seat_get_pointer (seat); + +	int x = -1, y = -1; +	GdkModifierType state = 0; +	GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (self)); +	gdk_window_get_device_position (window, pointer, &x, &y, &state); +	reset_hover_for_event (self, state, x, y); +} + +static void +stardict_view_map (GtkWidget *widget) +{ +	GTK_WIDGET_CLASS (stardict_view_parent_class)->map (widget); + +	GdkWindow *window = gtk_widget_get_window (widget); +	GdkDisplay *display = gdk_window_get_display (window); +	GdkKeymap *keymap = gdk_keymap_get_for_display (display); +	g_signal_connect (keymap, "state-changed", +		G_CALLBACK (on_keymap_state_changed), widget); +} + +static void +stardict_view_unmap (GtkWidget *widget) +{ +	GdkWindow *window = gtk_widget_get_window (widget); +	GdkDisplay *display = gdk_window_get_display (window); +	GdkKeymap *keymap = gdk_keymap_get_for_display (display); +	g_signal_handlers_disconnect_by_data (keymap, widget); + +	GTK_WIDGET_CLASS (stardict_view_parent_class)->unmap (widget); +} +  static gboolean  stardict_view_draw (GtkWidget *widget, cairo_t *cr)  { @@ -488,9 +727,13 @@ stardict_view_draw (GtkWidget *widget, cairo_t *cr)  		.cr = cr,  		.width = allocation.width,  		.height = 0, +  		.selection_layout = g_weak_ref_get (&self->selection),  		.selection_begin = self->selection_begin,  		.selection_end = self->selection_end, +		.hover_layout = g_weak_ref_get (&self->hover), +		.hover_begin = self->hover_begin, +		.hover_end = self->hover_end,  	};  	gint offset = -self->top_offset; @@ -516,80 +759,10 @@ stardict_view_draw (GtkWidget *widget, cairo_t *cr)  		gtk_style_context_restore (style);  	}  	g_clear_object (&ctx.selection_layout); +	g_clear_object (&ctx.hover_layout);  	return TRUE;  } -/// Figure out which layout is at given widget coordinates, and translate them. -static PangoLayout * -layout_at (StardictView *self, int *x, int *y) -{ -	GtkWidget *widget = GTK_WIDGET (self); -	int width = gtk_widget_get_allocated_width (widget); - -	// The algorithm here is a simplification of stardict_view_draw(). -	GtkStyleContext *style = gtk_widget_get_style_context (widget); -	GtkBorder padding = view_entry_get_padding (style); -	gint offset = -self->top_offset; -	for (GList *iter = self->entries; iter; iter = iter->next) -	{ -		ViewEntry *ve = iter->data; -		if (G_UNLIKELY (*y < offset)) -			break; - -		gint top_y = offset, word_y = 0, defn_y = 0; -		offset += view_entry_height (ve, &word_y, &defn_y); -		if (*y >= offset) -			continue; - -		if (*x >= width / 2) -		{ -			*x -= width / 2 + padding.left; -			*y -= top_y + defn_y; -			return ve->definition_layout; -		} -		else -		{ -			*x -= padding.left; -			*y -= top_y + word_y; -			return ve->word_layout; -		} -	} -	return NULL; -} - -/// Figure out a layout's coordinates. -static gboolean -layout_coords (StardictView *self, PangoLayout *layout, int *x, int *y) -{ -	GtkWidget *widget = GTK_WIDGET (self); -	int width = gtk_widget_get_allocated_width (widget); - -	// The algorithm here is a simplification of stardict_view_draw(). -	GtkStyleContext *style = gtk_widget_get_style_context (widget); -	GtkBorder padding = view_entry_get_padding (style); -	gint offset = -self->top_offset; -	for (GList *iter = self->entries; iter; iter = iter->next) -	{ -		ViewEntry *ve = iter->data; -		gint top_y = offset, word_y = 0, defn_y = 0; -		offset += view_entry_height (ve, &word_y, &defn_y); - -		if (layout == ve->definition_layout) -		{ -			*x = width / 2 + padding.left; -			*y = top_y + defn_y; -			return TRUE; -		} -		if (layout == ve->word_layout) -		{ -			*x = padding.left; -			*y = top_y + word_y; -			return TRUE; -		} -	} -	return FALSE; -} -  static void  stardict_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation)  { @@ -662,31 +835,11 @@ stardict_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)  	}  } -static int -layout_index_at (PangoLayout *layout, int x, int y) -{ -	int index = 0, trailing = 0; -	(void) pango_layout_xy_to_index (layout, -		x * PANGO_SCALE, -		y * PANGO_SCALE, -		&index, -		&trailing); - -	const char *text = pango_layout_get_text (layout) + index; -	while (trailing--) -	{ -		int len = g_utf8_next_char(text) - text; -		text += len; -		index += len; -	} -	return index; -} -  static void  publish_selection (StardictView *self, GdkAtom target)  {  	PangoLayout *layout = g_weak_ref_get (&self->selection); -	if (!layout || self->selection_begin == self->selection_end) +	if (!layout)  		return;  	// Unlike GtkLabel, we don't place the selection in PRIMARY immediately. @@ -694,7 +847,7 @@ publish_selection (StardictView *self, GdkAtom target)  	int len = strlen (text),  		s1 = MIN (self->selection_begin, self->selection_end),  		s2 = MAX (self->selection_begin, self->selection_end); -	if (s1 >= 0 && s1 <= len && s2 >= 0 && s2 <= len) +	if (s1 != s2 && s1 >= 0 && s1 <= len && s2 >= 0 && s2 <= len)  		gtk_clipboard_set_text (gtk_clipboard_get (target), text + s1, s2 - s1);  	g_object_unref (layout);  } @@ -702,22 +855,9 @@ publish_selection (StardictView *self, GdkAtom target)  static void  select_word_at (StardictView *self, int x, int y)  { -	PangoLayout *layout = layout_at (self, &x, &y); -	if (!layout) -		return; +	g_weak_ref_set (&self->selection, locate_word_at (self, +		x, y, &self->selection_begin, &self->selection_end)); -	const char *text = pango_layout_get_text (layout), *p = NULL; -	const char *begin = text + layout_index_at (layout, x, y), *end = begin; -	while ((p = g_utf8_find_prev_char (text, begin)) -		&& !g_unichar_isspace (g_utf8_get_char (p))) -		begin = p; -	gunichar c; -	while ((c = g_utf8_get_char (end)) && !g_unichar_isspace (c)) -		end = g_utf8_next_char (end); - -	g_weak_ref_set (&self->selection, layout); -	self->selection_begin = begin - text; -	self->selection_end = end - text;  	gtk_widget_queue_draw (GTK_WIDGET (self));  	publish_selection (self, GDK_SELECTION_PRIMARY);  } @@ -779,7 +919,7 @@ static gboolean  stardict_view_button_press_event (GtkWidget *widget, GdkEventButton *event)  {  	StardictView *self = STARDICT_VIEW (widget); -	if (gdk_event_triggers_context_menu((const GdkEvent *) event)) +	if (gdk_event_triggers_context_menu ((const GdkEvent *) event))  	{  		gtk_menu_popup_at_pointer (make_context_menu (self),  			(const GdkEvent *) event); @@ -806,6 +946,23 @@ stardict_view_button_press_event (GtkWidget *widget, GdkEventButton *event)  		->button_press_event (widget, event);  } +static gboolean +stardict_view_motion_notify_event (GtkWidget *widget, GdkEventMotion *event) +{ +	StardictView *self = STARDICT_VIEW (widget); +	reset_hover_for_event (self, event->state, event->x, event->y); +	return GTK_WIDGET_CLASS (stardict_view_parent_class) +		->motion_notify_event (widget, event); +} + +static gboolean +stardict_view_leave_notify_event +	(GtkWidget *widget, G_GNUC_UNUSED GdkEventCrossing *event) +{ +	reset_hover (STARDICT_VIEW (widget)); +	return GDK_EVENT_PROPAGATE; +} +  static void  on_drag_begin (GtkGestureDrag *drag, G_GNUC_UNUSED gdouble start_x,  	G_GNUC_UNUSED gdouble start_y, gpointer user_data) @@ -838,21 +995,49 @@ on_drag_update (G_GNUC_UNUSED GtkGestureDrag *drag,  	self->drag_last_offset = offset_y;  } +static gboolean +send_hover (StardictView *self) +{ +	PangoLayout *layout = g_weak_ref_get (&self->hover); +	if (!layout) +		return FALSE; + +	const char *text = pango_layout_get_text (layout); +	int len = strlen (text), +		s1 = MIN (self->hover_begin, self->hover_end), +		s2 = MAX (self->hover_begin, self->hover_end); +	if (s1 != s2 && s1 >= 0 && s1 <= len && s2 >= 0 && s2 <= len) +	{ +		gchar *word = g_strndup (text + s1, s2 - s1); +		g_signal_emit (self, view_signals[SEND], 0, word); +		g_free (word); +	} +	g_object_unref (layout); +	return TRUE; +} +  static void  on_select_begin (GtkGestureDrag *drag, gdouble start_x, gdouble start_y,  	gpointer user_data)  { +	// We probably don't need to check modifiers and mouse position again. +	StardictView *self = STARDICT_VIEW (user_data); +	GtkGesture *gesture = GTK_GESTURE (drag); +	if (send_hover (self)) +	{ +		gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED); +		return; +	} +  	// Despite our two gestures not being grouped up, claiming one doesn't  	// deny the other, and :exclusive isn't the opposite of :touch-only.  	// A non-NULL sequence indicates a touch event. -	GtkGesture *gesture = GTK_GESTURE (drag);  	if (gtk_gesture_get_last_updated_sequence (gesture))  	{ -		gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED); +		gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);  		return;  	} -	StardictView *self = STARDICT_VIEW (user_data);  	g_weak_ref_set (&self->selection, NULL);  	self->selection_begin = -1;  	self->selection_end = -1; @@ -862,7 +1047,7 @@ on_select_begin (GtkGestureDrag *drag, gdouble start_x, gdouble start_y,  	PangoLayout *layout = layout_at (self, &layout_x, &layout_y);  	if (!layout)  	{ -		gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED); +		gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);  		return;  	} @@ -881,7 +1066,7 @@ on_select_update (GtkGestureDrag *drag, gdouble offset_x, gdouble offset_y,  	PangoLayout *layout = g_weak_ref_get (&self->selection);  	if (!layout)  	{ -		gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED); +		gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);  		return;  	} @@ -892,7 +1077,7 @@ on_select_update (GtkGestureDrag *drag, gdouble offset_x, gdouble offset_y,  	if (!layout_coords (self, layout, &x, &y))  	{  		g_warning ("internal error: weakly referenced layout not found"); -		gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED); +		gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);  		goto out;  	} @@ -916,6 +1101,10 @@ on_select_end (G_GNUC_UNUSED GtkGestureDrag *drag,  static void  stardict_view_class_init (StardictViewClass *klass)  { +	view_signals[SEND] = g_signal_new ("send", +		G_TYPE_FROM_CLASS (klass), 0, 0, NULL, NULL, NULL, +		G_TYPE_NONE, 1, G_TYPE_STRING); +  	GObjectClass *object_class = G_OBJECT_CLASS (klass);  	object_class->finalize = stardict_view_finalize; @@ -923,11 +1112,15 @@ stardict_view_class_init (StardictViewClass *klass)  	widget_class->get_preferred_height = stardict_view_get_preferred_height;  	widget_class->get_preferred_width = stardict_view_get_preferred_width;  	widget_class->realize = stardict_view_realize; +	widget_class->map = stardict_view_map; +	widget_class->unmap = stardict_view_unmap;  	widget_class->draw = stardict_view_draw;  	widget_class->size_allocate = stardict_view_size_allocate;  	widget_class->screen_changed = stardict_view_screen_changed;  	widget_class->scroll_event = stardict_view_scroll_event;  	widget_class->button_press_event = stardict_view_button_press_event; +	widget_class->motion_notify_event = stardict_view_motion_notify_event; +	widget_class->leave_notify_event = stardict_view_leave_notify_event;  	gtk_widget_class_set_css_name (widget_class, "stardict-view");  } | 
