/* Update the cursor image if the pointer moved. */ static gboolean motion_notify_event (GtkWidget *text_view, GdkEventMotion *event) { gint x, y; gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y); set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y); return FALSE; }
/* Update the cursor image if the pointer moved. */ static gboolean motion_notify_event(GtkWidget * self, GdkEventMotion * event) { gint x, y; gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(self), GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y); set_cursor_if_appropriate(MARKDOWN_TEXTVIEW(self), x, y); gdk_window_get_pointer(self->window, NULL, NULL, NULL); return FALSE; }
/* Links can also be activated by clicking or tapping. */ static gboolean event_after (GtkWidget *text_view, GdkEvent *ev) { GtkTextIter start, end, iter; GtkTextBuffer *buffer; gdouble ex, ey; gint x, y; if (ev->type == GDK_BUTTON_RELEASE) { GdkEventButton *event; event = (GdkEventButton *)ev; if (event->button != GDK_BUTTON_PRIMARY) return FALSE; ex = event->x; ey = event->y; } else if (ev->type == GDK_TOUCH_END) { GdkEventTouch *event; event = (GdkEventTouch *)ev; ex = event->x; ey = event->y; } else return FALSE; buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)); /* we shouldn't follow a link if the user has selected something */ gtk_text_buffer_get_selection_bounds (buffer, &start, &end); if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end)) return FALSE; gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET, ex, ey, &x, &y); gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y); follow_if_link (text_view, &iter); return TRUE; }
/* Also update the cursor image if the window becomes visible * (e.g. when a window covering it got iconified). */ static gboolean visibility_notify_event(GtkWidget * self, GdkEventVisibility * event) { gint wx, wy, bx, by; gdk_window_get_pointer(self->window, &wx, &wy, NULL); gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(self), GTK_TEXT_WINDOW_WIDGET, wx, wy, &bx, &by); set_cursor_if_appropriate(MARKDOWN_TEXTVIEW(self), bx, by); return FALSE; }
/* Links can also be activated by clicking. */ static gboolean event_after (GtkWidget* text_view, GdkEvent* ev, UgBanner* banner) { GtkTextIter start, end, iter; GtkTextBuffer *buffer; GdkEventButton *event; gint x, y; GSList* slist; if (ev->type != GDK_BUTTON_RELEASE) return FALSE; event = (GdkEventButton *)ev; if (event->button != GDK_BUTTON_PRIMARY) return FALSE; buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)); /* we shouldn't follow a link if the user has selected something */ gtk_text_buffer_get_selection_bounds (buffer, &start, &end); if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end)) return FALSE; gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y); gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y); slist = gtk_text_iter_get_tags (&iter); if (slist) { switch (banner->status) { case UG_BANNER_DONATION: // ug_launch_uri ("https://sourceforge.net/p/urlget/donate/?source=navbar"); ug_launch_uri ("http://ugetdm.com/donate"); break; case UG_BANNER_SURVEY: ug_launch_uri ("http://ugetdm.com/survey"); break; } } if (slist) g_slist_free (slist); return FALSE; }
static gboolean textview_query_tooltip (GtkTextView *text_view, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer user_data) { GtkTextBuffer *buffer; guint32 state; gboolean res = FALSE; if (keyboard_mode) return FALSE; buffer = gtk_text_view_get_buffer (text_view); g_return_val_if_fail (buffer != NULL, FALSE); state = get_state (buffer); if ((state & E_BUFFER_TAGGER_STATE_IS_HOVERING_TOOLTIP) != 0) { gchar *url; GtkTextIter iter; gtk_text_view_window_to_buffer_coords ( text_view, GTK_TEXT_WINDOW_WIDGET, x, y, &x, &y); gtk_text_view_get_iter_at_location (text_view, &iter, x, y); url = get_url_at_iter (buffer, &iter); res = url && *url; if (res) { gchar *str; /* To Translators: The text is concatenated to a form: "Ctrl-click to open a link http://www.example.com" */ str = g_strconcat (_("Ctrl-click to open a link"), " ", url, NULL); gtk_tooltip_set_text (tooltip, str); g_free (str); } g_free (url); } return res; }
/* when the user right-clicks on a word, they want to check that word. * here, we move the cursor to the location of the clicked-upon word. * is this necessary? we could maybe just check the word from its * existing location... */ static gboolean button_press_event(GtkTextView *view, GdkEventButton *event, gpointer data) { if (event->button == 3) { gint x, y; GtkTextIter iter; gtk_text_view_window_to_buffer_coords(view, GTK_TEXT_WINDOW_TEXT, (int)event->x, (int)event->y, &x, &y); gtk_text_view_get_iter_at_location(view, &iter, x, y); gtk_text_buffer_place_cursor(gtk_text_view_get_buffer(view), &iter); } return FALSE; /* false: let gtk process this event, too. we don't want to eat any events. */ }
gboolean utl_gui_url_event_after (GtkWidget *textview, GdkEvent *ev, GSList **links_list) { GtkTextIter start, end, iter; GtkTextBuffer *buffer; GdkEventButton *event; gint x, y; GSList *tags = NULL, *tagp = NULL; GtkTextTag *tag; gchar *link; gint slink; gchar tmpbuf[BUFFER_SIZE]; if (ev->type != GDK_BUTTON_RELEASE) return FALSE; event = (GdkEventButton *) ev; if (event->button != 1) return FALSE; buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview)); gtk_text_buffer_get_selection_bounds (buffer, &start, &end); if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end)) return FALSE; gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (textview), GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y); gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (textview), &iter, x, y); tags = gtk_text_iter_get_tags (&iter); for (tagp = tags; tagp != NULL; tagp = tagp->next) { tag = tagp->data; slink = (gint) g_object_get_data (G_OBJECT (tag), "link"); if (slink != 0) { link = g_slist_nth_data (*links_list, slink-1); g_snprintf (tmpbuf, BUFFER_SIZE, "\"%s\"", link); utl_run_helper (tmpbuf, utl_get_link_type (link)); break; } } if (tags) g_slist_free (tags); return FALSE; }
static gboolean details_visibility_notify_event (GtkWidget *text_view, GdkEventVisibility *event, GucharmapCharmap *charmap) { gint wx, wy, bx, by; gdk_window_get_pointer (gtk_widget_get_window (text_view), &wx, &wy, NULL); gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET, wx, wy, &bx, &by); set_cursor_if_appropriate (charmap, bx, by); return FALSE; }
static gboolean textview_motion_notify_event (GtkTextView *textview, GdkEventMotion *event) { gint x, y; g_return_val_if_fail (GTK_IS_TEXT_VIEW (textview), FALSE); gtk_text_view_window_to_buffer_coords ( textview, GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y); update_mouse_cursor (textview, x, y); return FALSE; }
/* * Update the cursor image if the pointer moved. */ static gboolean motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, EntryProperties *eprop) { gint x, y; gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y); set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y, eprop); /* store coordinates */ eprop->priv->bx = x; eprop->priv->by = y; return FALSE; }
static void update_ctrl_state (GtkTextView *textview, gboolean ctrl_is_down) { GtkTextBuffer *buffer; gint x, y; buffer = gtk_text_view_get_buffer (textview); if (buffer) { if (((get_state (buffer) & E_BUFFER_TAGGER_STATE_CTRL_DOWN) != 0) != (ctrl_is_down != FALSE)) { update_state (buffer, E_BUFFER_TAGGER_STATE_CTRL_DOWN, ctrl_is_down != FALSE); } get_pointer_position (textview, &x, &y); gtk_text_view_window_to_buffer_coords (textview, GTK_TEXT_WINDOW_WIDGET, x, y, &x, &y); update_mouse_cursor (textview, x, y); } }
CAMLprim value ml_gtk_text_view_window_to_buffer_coords (value tv, value tt, value x, value y) { CAMLparam4(tv,tt,x,y); CAMLlocal1(res); int bx,by = 0; gtk_text_view_window_to_buffer_coords(GtkTextView_val(tv), Text_window_type_val(tt), Int_val(x),Int_val(y), &bx,&by); res = alloc_tuple(2); Store_field(res,0,Val_int(bx)); Store_field(res,1,Val_int(by)); CAMLreturn(res); }
static gboolean cb_button_press_event(GtkWidget *view, GdkEventButton *event) { GtkTextIter iter, start, end; gint x, y; GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)); if ((event->button) == 3 && (event->type == GDK_BUTTON_PRESS)) { gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(view), gtk_text_view_get_window_type(GTK_TEXT_VIEW(view), event->window), (gint)event->x, (gint)event->y, &x, &y); gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(view), &iter, x, y); gtk_text_buffer_get_selection_bounds(buffer, &start, &end); if (!gtk_text_iter_in_range(&iter, &start, &end)) gtk_text_buffer_place_cursor(buffer, &iter); } return FALSE; }
static gboolean motion_cb (GtkWidget *w, GdkEventMotion *ev, gpointer d) { gint x, y; GSList *tags = NULL, *tagp = NULL; GtkTextIter iter; gboolean hovering = FALSE; gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (w), GTK_TEXT_WINDOW_WIDGET, ev->x, ev->y, &x, &y); gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (w), &iter, x, y); tags = gtk_text_iter_get_tags (&iter); for (tagp = tags; tagp != NULL; tagp = tagp->next) { GtkTextTag *tag = tagp->data; gint link = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tag), "is_link")); if (link) { hovering = TRUE; break; } } if (hovering != hovering_over_link) { hovering_over_link = hovering; if (hovering_over_link) gdk_window_set_cursor (gtk_text_view_get_window (GTK_TEXT_VIEW (w), GTK_TEXT_WINDOW_TEXT), hand); else gdk_window_set_cursor (gtk_text_view_get_window (GTK_TEXT_VIEW (w), GTK_TEXT_WINDOW_TEXT), normal); } if (tags) g_slist_free (tags); gdk_window_get_pointer (gtk_widget_get_window (w), NULL, NULL, NULL); return FALSE; }
static gboolean textview_visibility_notify_event (GtkTextView *textview, GdkEventVisibility *event) { gint wx, wy, bx, by; g_return_val_if_fail (GTK_IS_TEXT_VIEW (textview), FALSE); get_pointer_position (textview, &wx, &wy); gtk_text_view_window_to_buffer_coords ( textview, GTK_TEXT_WINDOW_WIDGET, wx, wy, &bx, &by); update_mouse_cursor (textview, bx, by); return FALSE; }
/* * Also update the cursor image if the window becomes visible * (e.g. when a window covering it got iconified). */ static gboolean visibility_notify_event (GtkWidget *text_view, G_GNUC_UNUSED GdkEventVisibility *event, GdauiCloud *cloud) { gint wx, wy, bx, by; GdkDeviceManager *manager; GdkDevice *pointer; manager = gdk_display_get_device_manager (gtk_widget_get_display (text_view)); pointer = gdk_device_manager_get_client_pointer (manager); gdk_window_get_device_position (gtk_widget_get_window (text_view), pointer, &wx, &wy, NULL); gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET, wx, wy, &bx, &by); set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), bx, by, cloud); return FALSE; }
/* on_view_event_after */ static gboolean _on_view_event_after(GtkWidget * widget, GdkEvent * event, gpointer data) { GHtml * ghtml = data; GdkEventButton * eb; GtkTextIter start; GtkTextIter end; gint x; gint y; GtkTextIter iter; GSList * tags; GSList * p; char * link = NULL; gchar * url; if(event->type != GDK_BUTTON_RELEASE || event->button.button != 1) return FALSE; eb = &event->button; gtk_text_buffer_get_selection_bounds(ghtml->tbuffer, &start, &end); if(gtk_text_iter_get_offset(&start) != gtk_text_iter_get_offset(&end)) return FALSE; gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_WIDGET, eb->x, eb->y, &x, &y); gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(widget), &iter, x, y); tags = gtk_text_iter_get_tags(&iter); for(p = tags; p != NULL; p = p->next) if((link = g_object_get_data(G_OBJECT(p->data), "link")) != NULL) break; if(tags != NULL) g_slist_free(tags); if(link == NULL) return FALSE; url = (ghtml->base != NULL) ? ghtml->base : _history_get_location( ghtml->current); if((url = _ghtml_make_url(url, link)) != NULL) surfer_open(ghtml->surfer, url); else surfer_open(ghtml->surfer, link); g_free(url); return FALSE; }
static gboolean _text_view_click_handler(GtkWidget *widget, GdkEvent *event) { GtkTextView *text_view = GTK_TEXT_VIEW(widget); if (event->type == GDK_BUTTON_RELEASE) { GdkEventButton *button_event = GDK_EVENT_BUTTON(event); if (button_event->button == 1) { GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(text_view); gint x; gint y; GtkTextIter text_iter; gtk_text_view_window_to_buffer_coords(text_view, GTK_TEXT_WINDOW_WIDGET, button_event->x, button_event->y, &x, &y); gtk_text_view_get_iter_at_location(text_view, &text_iter, x, y); { GSList *text_tag_list = gtk_text_iter_get_tags(&text_iter); GSList *text_tag_list_item; for (text_tag_list_item = text_tag_list; text_tag_list_item != NULL; text_tag_list_item = text_tag_list_item->next) { GtkTextTag *text_tag = GTK_TEXT_TAG(text_tag_list_item->data); if (g_object_get_data(G_OBJECT(text_tag), "column_type") != NULL) { gtk_text_buffer_place_cursor(text_buffer); break; } } if (text_tag_list != NULL) g_slist_free(text_tag_list); } return TRUE; } } return FALSE; }
static gboolean mouse_click_callback(GtkWidget *text_view, GdkEventButton *event) { gint x, y; gchar *url = NULL; if (event->type != GDK_2BUTTON_PRESS) return FALSE; gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(text_view), GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y); get_url_at_location(&url, GTK_TEXT_VIEW(text_view), x, y); if (url != NULL) { open_url(text_view, url); } return TRUE; }
static gboolean chatroom_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) { gint wx, wy, bx, by; GtkTextView *chatroom = GTK_TEXT_VIEW(widget); GtkTextBuffer *buffer = gtk_text_view_get_buffer(chatroom); GtkTextTag *link_tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "link"); GdkWindow *window = gtk_text_view_get_window(chatroom, GTK_TEXT_WINDOW_TEXT); GtkTextIter iter; if(event->type == GDK_MOTION_NOTIFY) { GdkEventMotion *motion_ev = (GdkEventMotion *)event; wx = motion_ev->x; wy = motion_ev->y; gtk_text_view_window_to_buffer_coords(chatroom, GTK_TEXT_WINDOW_TEXT, wx, wy, &bx, &by); gtk_text_view_get_iter_at_location(chatroom, &iter, bx, by); if(gtk_text_iter_has_tag(&iter, link_tag)) { chatroom_enable_hand_cursor(window, TRUE); } else { chatroom_enable_hand_cursor(window, FALSE); } } return FALSE; }
/* Looks at all tags covering the position (x, y) in the text view, * and if one of them is a link, change the cursor to the "hands" cursor * typically used by web browsers. */ static gboolean motion_notify_event (GtkWidget* tv_widget, GdkEventMotion* event, UgBanner* banner) { GtkTextView* text_view; gint x, y; gboolean hovering = FALSE; GSList* slist; GtkTextIter iter; text_view = GTK_TEXT_VIEW (tv_widget); gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y); // set cursor if appropriate gtk_text_view_get_iter_at_location (text_view, &iter, x, y); slist = gtk_text_iter_get_tags (&iter); if (slist) hovering = TRUE; if (banner->hovering_over_link != hovering) { banner->hovering_over_link = hovering; if (banner->hovering_over_link) { gdk_window_set_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), hand_cursor); } else { gdk_window_set_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), regular_cursor); } } if (slist) g_slist_free (slist); return FALSE; }
static gboolean query_tooltip_text_view_cb (GtkWidget *widget, gint x, gint y, gboolean keyboard_tip, GtkTooltip *tooltip, gpointer data) { GtkTextTag *tag = data; GtkTextIter iter; GtkTextView *text_view = GTK_TEXT_VIEW (widget); GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view); if (keyboard_tip) { gint offset; g_object_get (buffer, "cursor-position", &offset, NULL); gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset); } else { gint bx, by, trailing; gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_TEXT, x, y, &bx, &by); gtk_text_view_get_iter_at_position (text_view, &iter, &trailing, bx, by); } if (gtk_text_iter_has_tag (&iter, tag)) gtk_tooltip_set_text (tooltip, "Tooltip on text tag"); else return FALSE; return TRUE; }
static void about_textview_uri_update(GtkWidget *textview, gint x, gint y) { GtkTextBuffer *buffer; GtkTextIter start_iter, end_iter; gchar *uri = NULL; gboolean same; buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); if (x != -1 && y != -1) { gint bx, by; GtkTextIter iter; GSList *tags; GSList *cur; gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(textview), GTK_TEXT_WINDOW_WIDGET, x, y, &bx, &by); gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(textview), &iter, bx, by); tags = gtk_text_iter_get_tags(&iter); for (cur = tags; cur != NULL; cur = cur->next) { GtkTextTag *tag = cur->data; char *name; g_object_get(G_OBJECT(tag), "name", &name, NULL); if (strcmp(name, "link") == 0 && get_tag_range(&iter, tag, &start_iter, &end_iter)) { uri = gtk_text_iter_get_text(&start_iter, &end_iter); } g_free(name); if (uri) { break; } } g_slist_free(tags); } /* compare previous hovered link and this one (here links must be unique in text buffer otherwise ClickableText structures should be used as in textview.c) */ same = (uri != NULL && uri_hover != NULL && strcmp((char*)uri, (char*)uri_hover) == 0); if (same == FALSE) { GdkWindow *window; if (uri_hover) { gtk_text_buffer_remove_tag_by_name(buffer, "link-hover", &uri_hover_start_iter, &uri_hover_end_iter); } uri_hover = uri; if (uri) { uri_hover_start_iter = start_iter; uri_hover_end_iter = end_iter; gtk_text_buffer_apply_tag_by_name(buffer, "link-hover", &start_iter, &end_iter); } window = gtk_text_view_get_window(GTK_TEXT_VIEW(textview), GTK_TEXT_WINDOW_TEXT); if (!hand_cursor) hand_cursor = gdk_cursor_new(GDK_HAND2); if (!text_cursor) text_cursor = gdk_cursor_new(GDK_XTERM); gdk_window_set_cursor(window, uri ? hand_cursor : text_cursor); } }
static void chat_text_view_populate_popup (EmpathyChatTextView *view, GtkMenu *menu, gpointer user_data) { EmpathyChatTextViewPriv *priv; GtkTextTagTable *table; GtkTextTag *tag; gint x, y; GtkTextIter iter, start, end; GtkWidget *item; gchar *str = NULL; priv = GET_PRIV (view); /* Clear menu item */ if (gtk_text_buffer_get_char_count (priv->buffer) > 0) { item = gtk_menu_item_new (); gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); item = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLEAR, NULL); gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); g_signal_connect (item, "activate", G_CALLBACK (chat_text_view_clear_view_cb), view); } /* Link context menu items */ table = gtk_text_buffer_get_tag_table (priv->buffer); tag = gtk_text_tag_table_lookup (table, EMPATHY_CHAT_TEXT_VIEW_TAG_LINK); gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y); gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view), GTK_TEXT_WINDOW_WIDGET, x, y, &x, &y); gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter, x, y); start = end = iter; if (gtk_text_iter_backward_to_tag_toggle (&start, tag) && gtk_text_iter_forward_to_tag_toggle (&end, tag)) { str = gtk_text_buffer_get_text (priv->buffer, &start, &end, FALSE); } if (EMP_STR_EMPTY (str)) { g_free (str); return; } /* NOTE: Set data just to get the string freed when not needed. */ g_object_set_data_full (G_OBJECT (menu), "url", str, (GDestroyNotify) g_free); item = gtk_menu_item_new (); gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); item = gtk_menu_item_new_with_mnemonic (_("_Copy Link Address")); g_signal_connect (item, "activate", G_CALLBACK (chat_text_view_copy_address_cb), str); gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); item = gtk_menu_item_new_with_mnemonic (_("_Open Link")); g_signal_connect (item, "activate", G_CALLBACK (chat_text_view_open_address_cb), str); gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); }
/************************************************************************** Click a link. **************************************************************************/ static gboolean event_after(GtkWidget *text_view, GdkEventButton *event) { GtkTextIter start, end, iter; GtkTextBuffer *buffer; GSList *tags, *tagp; gint x, y; struct tile *ptile = NULL; if (event->type != GDK_BUTTON_RELEASE || event->button != 1) { return FALSE; } buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view)); /* We shouldn't follow a link if the user has selected something. */ gtk_text_buffer_get_selection_bounds(buffer, &start, &end); if (gtk_text_iter_get_offset(&start) != gtk_text_iter_get_offset(&end)) { return FALSE; } gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET, event->x, event->y, &x, &y); gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(text_view), &iter, x, y); if ((tags = gtk_text_iter_get_tags(&iter))) { for (tagp = tags; tagp; tagp = tagp->next) { GtkTextTag *tag = tagp->data; enum text_link_type type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tag), "type")); if (type != 0) { /* This is a link. */ int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tag), "id")); ptile = NULL; /* Real type is type - 1. * See comment in apply_text_tag() for g_object_set_data(). */ type--; switch (type) { case TLT_CITY: { struct city *pcity = game_city_by_number(id); if (pcity) { ptile = client_city_tile(pcity); } else { output_window_append(ftc_client, _("This city isn't known!")); } } break; case TLT_TILE: ptile = index_to_tile(id); if (!ptile) { output_window_append(ftc_client, _("This tile doesn't exist in this game!")); } break; case TLT_UNIT: { struct unit *punit = game_unit_by_number(id); if (punit) { ptile = unit_tile(punit); } else { output_window_append(ftc_client, _("This unit isn't known!")); } } break; } if (ptile) { center_tile_mapcanvas(ptile); link_mark_restore(type, id); gtk_widget_grab_focus(GTK_WIDGET(map_canvas)); } } } g_slist_free(tags); } return FALSE; }
gint motion_notify_event(GtkWidget *widget, GdkEventMotion *event) { gint x, y; GdkModifierType mask; GtkTextIter iter; guint offset; gint buffer_x, buffer_y; GdkRectangle location; gboolean too_far=FALSE; #ifdef __WIN32__ HCURSOR hCursor; #else GdkCursor *cursor; #endif // LOG(LOG_DEBUG, "IN : motion_notify_event(x=%f,y=%f (%d %d))", event->x, event->y, buffer_x, buffer_y); // If you don't convert position as buffer origin, // position will be invalid when scrolling gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_TEXT, (gint)(event->x), (gint)(event->y), &buffer_x, &buffer_y); gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(widget), &iter, buffer_x, buffer_y); offset = gtk_text_iter_get_offset(&iter); gtk_text_view_get_iter_location(GTK_TEXT_VIEW(widget), &iter, &location); if((buffer_x > location.x + font_width) || (buffer_x < location.x - font_width)) too_far = TRUE; else too_far = FALSE; #ifdef __WIN32__ if(scan_link(offset) && !too_far){ hCursor = LoadCursor(NULL, IDC_HAND); // Because IDC_HAND can not be used in NT if(hCursor == 0) hCursor = LoadCursor(NULL, IDC_ARROW); } else { hCursor = LoadCursor(NULL, IDC_IBEAM); } SetCursor(hCursor); #else if(scan_link(offset) && !too_far){ cursor = gdk_cursor_new (CURSOR_LINK); } else { cursor = gdk_cursor_new(CURSOR_NORMAL); } gdk_window_set_cursor(gtk_text_view_get_window(GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_TEXT), cursor); gdk_cursor_unref(cursor); gdk_window_get_pointer(widget->window, &x, &y, &mask); #endif // LOG(LOG_DEBUG, "OUT : motion_notify_event()"); if(event->state & GDK_BUTTON1_MASK) return(FALSE); else return(TRUE); }
static void dma_sparse_view_paint_margin (DmaSparseView *view, GdkEventExpose *event) { GtkTextView *text_view; GdkWindow *win; PangoLayout *layout; gint y1, y2; gint y, height; gchar str [16]; gint margin_width; gint margin_length; gint text_width; DmaSparseIter buf_iter; GtkTextIter text_iter; guint prev_address = G_MAXUINT; text_view = GTK_TEXT_VIEW (view); if (!view->priv->show_line_numbers && !view->priv->show_line_markers) { gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT, 0); return; } win = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_LEFT); y1 = event->area.y; y2 = y1 + event->area.height; /* get the extents of the line printing */ gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_LEFT, 0, y1, NULL, &y1); gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_LEFT, 0, y2, NULL, &y2); /* set size. */ g_snprintf (str, sizeof (str), "0x%X", G_MAXUINT); margin_length = strlen(str) - 2; layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), str); pango_layout_get_pixel_size (layout, &text_width, NULL); pango_layout_set_width (layout, text_width); pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); /* determine the width of the left margin. */ if (view->priv->show_line_numbers) margin_width = text_width + 4; else margin_width = 0; if (view->priv->show_line_markers) margin_width += GUTTER_PIXMAP; g_return_if_fail (margin_width != 0); gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_LEFT, margin_width); /* Display all addresses */ dma_sparse_iter_copy (&buf_iter, &view->priv->start); gtk_text_buffer_get_start_iter (gtk_text_view_get_buffer (text_view), &text_iter); /* Skip line while position doesn't need to be repaint */ gtk_text_view_get_line_yrange (text_view, &text_iter, &y, &height); if (y < y1) { do { if (!dma_sparse_iter_forward_lines (&buf_iter, 1)) return; if (!gtk_text_iter_forward_line (&text_iter)) return; gtk_text_view_get_line_yrange (text_view, &text_iter, &y, &height); } while (y < y1); } /* Display address */ do { gint pos; guint address; gtk_text_view_buffer_to_window_coords (text_view, GTK_TEXT_WINDOW_LEFT, 0, y, NULL, &pos); address = dma_sparse_iter_get_address (&buf_iter); if (view->priv->show_line_numbers) { g_snprintf (str, sizeof (str),"0x%0*lX", margin_length, (long unsigned int)address); pango_layout_set_markup (layout, str, -1); gtk_paint_layout (gtk_widget_get_style (GTK_WIDGET (view)), win, gtk_widget_get_state (GTK_WIDGET (view)), FALSE, NULL, GTK_WIDGET (view), NULL, text_width + 2, pos, layout); } /* Display marker */ if ((prev_address != address) && (view->priv->show_line_markers)) { gint current_marker = dma_sparse_buffer_get_marks (view->priv->buffer, address); if (current_marker) { gint x; if (view->priv->show_line_numbers) x = text_width + 4; else x = 0; draw_line_markers (view, current_marker, x, pos); prev_address = address; } } if (!dma_sparse_iter_forward_lines (&buf_iter, 1)) return; if (!gtk_text_iter_forward_line (&text_iter)) return; gtk_text_view_get_line_yrange (text_view, &text_iter, &y, &height); } while (y < y2); g_object_unref (G_OBJECT (layout)); }
static gint line_numbers_expose (GtkWidget *widget, GdkEventExpose *event) { GtkTextView *text_view; GdkWindow *win; // GtkStyle *style; PangoLayout *layout; PangoAttrList *alist; PangoAttribute *attr; GArray *numbers; GArray *pixels; gint y1, y2; gint count; gint layout_width; gint justify_width = 0; gint i; // gchar *str; gchar str [8]; /* we don't expect more than ten million lines */ GdkGC *gc; gint height; if (line_number_visible){{{{{ // omit calculation text_view = GTK_TEXT_VIEW (widget); /* See if this expose is on the line numbers window */ /* left_win = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_LEFT); right_win = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_RIGHT); if (event->window == left_win) { type = GTK_TEXT_WINDOW_LEFT; target = event->window; } else if (event->window == right_win) { type = GTK_TEXT_WINDOW_RIGHT; target = right_win; } else return FALSE; */ win = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_LEFT); if (event->window != win) return FALSE; // style = gtk_style_copy (widget->style); // style = gtk_style_copy (gtk_widget_get_default_style()); y1 = event->area.y; y2 = y1 + event->area.height; gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_LEFT, 0, y1, NULL, &y1); gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_LEFT, 0, y2, NULL, &y2); numbers = g_array_new (FALSE, FALSE, sizeof (gint)); pixels = g_array_new (FALSE, FALSE, sizeof (gint)); get_lines (text_view, y1, y2, pixels, numbers, &count); /* a zero-lined document should display a "1"; we don't need to worry about scrolling effects of the text widget in this special case */ if (count == 0) { gint y = 0; gint n = 0; count = 1; g_array_append_val (pixels, y); g_array_append_val (numbers, n); } DV({g_print("Painting line numbers %d - %d\n", g_array_index(numbers, gint, 0), g_array_index(numbers, gint, count - 1)); }); layout = gtk_widget_create_pango_layout (widget, ""); // str = g_strdup_printf ("%d", gtk_text_buffer_get_line_count(text_view->buffer)); g_snprintf (str, sizeof (str), "%d", MAX (99, gtk_text_buffer_get_line_count(text_view->buffer))); pango_layout_set_text (layout, str, -1); // g_free (str); pango_layout_get_pixel_size (layout, &layout_width, NULL); min_number_window_width = calculate_min_number_window_width(widget); if (layout_width > min_number_window_width) gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT, layout_width + margin + submargin); else { // if ((gtk_text_view_get_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT) - 5) > layout_width) { gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT, min_number_window_width + margin + submargin); // } justify_width = min_number_window_width - layout_width; } pango_layout_set_width (layout, layout_width); pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); alist = pango_attr_list_new(); attr = pango_attr_foreground_new( widget->style->text_aa->red, widget->style->text_aa->green, widget->style->text_aa->blue); attr->start_index = 0; attr->end_index = G_MAXUINT; pango_attr_list_insert(alist, attr); pango_layout_set_attributes(layout, alist); pango_attr_list_unref(alist); /* Draw fully internationalized numbers! */ i = 0; while (i < count) { gint pos; gtk_text_view_buffer_to_window_coords (text_view, GTK_TEXT_WINDOW_LEFT, 0, g_array_index (pixels, gint, i), NULL, &pos); // str = g_strdup_printf ("%d", g_array_index (numbers, gint, i) + 1); g_snprintf (str, sizeof (str), "%d", g_array_index (numbers, gint, i) + 1); pango_layout_set_text (layout, str, -1); gtk_paint_layout (widget->style, win, GTK_WIDGET_STATE (widget), FALSE, NULL, widget, NULL, #if GTK_CHECK_VERSION(2, 6, 0) // Is this solution??? layout_width + justify_width + margin / 2 + 1, #else layout_width + justify_width + margin / 2, #endif pos, layout); // g_free (str); ++i; } g_array_free (pixels, TRUE); g_array_free (numbers, TRUE); g_object_unref (G_OBJECT (layout)); // g_object_ref (G_OBJECT (style)); /* don't stop emission, need to draw children */ }}}}}
static gboolean on_view_draw (GtkSourceView *view, cairo_t *cr, GtkSourceGutter *gutter) { GdkWindow *window; GtkTextView *text_view; GArray *sizes; GdkRectangle clip; gint x, y; gint y1, y2; GArray *numbers; GArray *pixels; GArray *heights; GtkTextIter cur; gint cur_line; gint count; gint i; GList *item; GtkTextIter start; GtkTextIter end; GtkTextBuffer *buffer; GdkRectangle background_area; GdkRectangle cell_area; GtkTextIter selection_start; GtkTextIter selection_end; gboolean has_selection; gint idx; GtkStyleContext *style_context; GdkRGBA fg_color; window = gtk_source_gutter_get_window (gutter); if (window == NULL || !gtk_cairo_should_draw_window (cr, window)) { return FALSE; } gtk_cairo_transform_to_window (cr, GTK_WIDGET (view), window); text_view = GTK_TEXT_VIEW (view); if (!gdk_cairo_get_clip_rectangle (cr, &clip)) { return FALSE; } gutter->priv->is_drawing = TRUE; buffer = gtk_text_view_get_buffer (text_view); gdk_window_get_pointer (window, &x, &y, NULL); y1 = clip.y; y2 = y1 + clip.height; /* get the extents of the line printing */ gtk_text_view_window_to_buffer_coords (text_view, gutter->priv->window_type, 0, y1, NULL, &y1); gtk_text_view_window_to_buffer_coords (text_view, gutter->priv->window_type, 0, y2, NULL, &y2); numbers = g_array_new (FALSE, FALSE, sizeof (gint)); pixels = g_array_new (FALSE, FALSE, sizeof (gint)); heights = g_array_new (FALSE, FALSE, sizeof (gint)); sizes = g_array_new (FALSE, FALSE, sizeof (gint)); calculate_gutter_size (gutter, sizes); i = 0; x = 0; background_area.x = 0; background_area.height = get_lines (text_view, y1, y2, pixels, heights, numbers, &count, &start, &end); cell_area.x = gutter->priv->xpad; cell_area.height = background_area.height; gtk_text_view_buffer_to_window_coords (text_view, gutter->priv->window_type, 0, g_array_index (pixels, gint, 0), NULL, &background_area.y); cell_area.y = background_area.y; item = gutter->priv->renderers; idx = 0; style_context = gtk_widget_get_style_context (GTK_WIDGET (view)); gtk_style_context_get_color (style_context, gtk_widget_get_state (GTK_WIDGET (view)), &fg_color); gdk_cairo_set_source_rgba (cr, &fg_color); while (item) { Renderer *renderer = item->data; gint xpad; gint width; width = g_array_index (sizes, gint, idx++); if (gtk_source_gutter_renderer_get_visible (renderer->renderer)) { gtk_source_gutter_renderer_get_padding (renderer->renderer, &xpad, NULL); background_area.width = width; cell_area.width = width - 2 * xpad; cell_area.x = background_area.x + xpad; cairo_save (cr); gdk_cairo_rectangle (cr, &background_area); cairo_clip (cr); gtk_source_gutter_renderer_begin (renderer->renderer, cr, &background_area, &cell_area, &start, &end); cairo_restore (cr); background_area.x += background_area.width; } item = g_list_next (item); } gtk_text_buffer_get_iter_at_mark (buffer, &cur, gtk_text_buffer_get_insert (buffer)); cur_line = gtk_text_iter_get_line (&cur); gtk_text_buffer_get_selection_bounds (buffer, &selection_start, &selection_end); has_selection = !gtk_text_iter_equal (&selection_start, &selection_end); if (has_selection) { if (!gtk_text_iter_starts_line (&selection_start)) { gtk_text_iter_set_line_offset (&selection_start, 0); } if (!gtk_text_iter_ends_line (&selection_end)) { gtk_text_iter_forward_to_line_end (&selection_end); } } for (i = 0; i < count; ++i) { gint pos; gint line_to_paint; end = start; if (!gtk_text_iter_ends_line (&end)) { gtk_text_iter_forward_to_line_end (&end); } gtk_text_view_buffer_to_window_coords (text_view, gutter->priv->window_type, 0, g_array_index (pixels, gint, i), NULL, &pos); line_to_paint = g_array_index (numbers, gint, i); background_area.y = pos; background_area.height = g_array_index (heights, gint, i); background_area.x = 0; idx = 0; for (item = gutter->priv->renderers; item; item = g_list_next (item)) { Renderer *renderer; gint width; GtkSourceGutterRendererState state; gint xpad; gint ypad; renderer = item->data; width = g_array_index (sizes, gint, idx++); if (!gtk_source_gutter_renderer_get_visible (renderer->renderer)) { continue; } gtk_source_gutter_renderer_get_padding (renderer->renderer, &xpad, &ypad); background_area.width = width; cell_area.y = background_area.y + ypad; cell_area.height = background_area.height - 2 * ypad; cell_area.x = background_area.x + xpad; cell_area.width = background_area.width - 2 * xpad; state = GTK_SOURCE_GUTTER_RENDERER_STATE_NORMAL; if (line_to_paint == cur_line) { state |= GTK_SOURCE_GUTTER_RENDERER_STATE_CURSOR; } if (has_selection && gtk_text_iter_in_range (&start, &selection_start, &selection_end)) { state |= GTK_SOURCE_GUTTER_RENDERER_STATE_SELECTED; } if (renderer->prelit >= 0 && cell_area.y <= renderer->prelit && cell_area.y + cell_area.height >= renderer->prelit) { state |= GTK_SOURCE_GUTTER_RENDERER_STATE_PRELIT; } gtk_source_gutter_renderer_query_data (renderer->renderer, &start, &end, state); cairo_save (cr); gdk_cairo_rectangle (cr, &background_area); cairo_clip (cr); /* Call render with correct area */ gtk_source_gutter_renderer_draw (renderer->renderer, cr, &background_area, &cell_area, &start, &end, state); cairo_restore (cr); background_area.x += background_area.width; } gtk_text_iter_forward_line (&start); } for (item = gutter->priv->renderers; item; item = g_list_next (item)) { Renderer *renderer = item->data; if (gtk_source_gutter_renderer_get_visible (renderer->renderer)) { gtk_source_gutter_renderer_end (renderer->renderer); } } g_array_free (numbers, TRUE); g_array_free (pixels, TRUE); g_array_free (heights, TRUE); g_array_free (sizes, TRUE); gutter->priv->is_drawing = FALSE; return FALSE; }