summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Faure <billiob@gmail.com>2018-12-12 21:42:42 +0100
committerBoris Faure <billiob@gmail.com>2018-12-13 16:41:29 +0100
commit64b58bb09452ae9799c477aef2767f9aecb981d9 (patch)
tree2ec3673078f647f8d0296224e02456042093b945
parent6327d714aa5632ab59cb29d1a792f012f7fb65a2 (diff)
termio/win: handle hyperlinks on right click
Fix segfault
-rw-r--r--src/bin/termio.c135
-rw-r--r--src/bin/win.c17
2 files changed, 114 insertions, 38 deletions
diff --git a/src/bin/termio.c b/src/bin/termio.c
index f24a0fa..abf6ae6 100644
--- a/src/bin/termio.c
+++ b/src/bin/termio.c
@@ -51,7 +51,7 @@ struct _Termio
51 int button; 51 int button;
52 } mouse; 52 } mouse;
53 struct { 53 struct {
54 char *string; 54 const char *string;
55 int x1, y1, x2, y2; 55 int x1, y1, x2, y2;
56 int suspend; 56 int suspend;
57 uint16_t id; 57 uint16_t id;
@@ -819,12 +819,40 @@ _should_inline(const Evas_Object *obj)
819 return EINA_TRUE; 819 return EINA_TRUE;
820} 820}
821 821
822const char * 822/* Need to be freed */
823const char *
823termio_link_get(const Evas_Object *obj) 824termio_link_get(const Evas_Object *obj)
824{ 825{
825 Termio *sd = evas_object_smart_data_get(obj); 826 Termio *sd = evas_object_smart_data_get(obj);
826 EINA_SAFETY_ON_NULL_RETURN_VAL(sd, NULL); 827 EINA_SAFETY_ON_NULL_RETURN_VAL(sd, NULL);
827 return sd->link.string; 828 const char *link;
829
830 if (!sd->link.string && !sd->link.id)
831 return NULL;
832 link = sd->link.string;
833 if (sd->link.id)
834 {
835 Term_Link *hl = &sd->pty->hl.links[sd->link.id];
836 if (!hl->url)
837 return NULL;
838 link = hl->url;
839 }
840 if (link_is_url(link))
841 {
842 if (casestartswith(link, "file://"))
843 {
844 // TODO: decode string: %XX -> char
845 link = link + sizeof("file://") - 1;
846 /* Handle cases where / is ommitted: file://HOSTNAME/home/ */
847 if (link[0] != '/')
848 {
849 link = strchr(link, '/');
850 if (!link)
851 return NULL;
852 }
853 }
854 }
855 return strdup(link);
828} 856}
829 857
830static void 858static void
@@ -834,33 +862,32 @@ _activate_link(Evas_Object *obj, Eina_Bool may_inline)
834 Config *config; 862 Config *config;
835 char buf[PATH_MAX], *s, *escaped; 863 char buf[PATH_MAX], *s, *escaped;
836 const char *path = NULL, *cmd = NULL; 864 const char *path = NULL, *cmd = NULL;
865 const char *link = NULL;
837 Eina_Bool url = EINA_FALSE, email = EINA_FALSE, handled = EINA_FALSE; 866 Eina_Bool url = EINA_FALSE, email = EINA_FALSE, handled = EINA_FALSE;
838 867
839 EINA_SAFETY_ON_NULL_RETURN(sd); 868 EINA_SAFETY_ON_NULL_RETURN(sd);
840 config = sd->config; 869 config = sd->config;
841 if (!config) return; 870 if (!config) return;
842 if (!config->active_links) return; 871 if (!config->active_links) return;
843 if (!sd->link.string) return; 872
844 if (link_is_url(sd->link.string)) 873 link = termio_link_get(obj);
845 { 874 if (!link)
846 if (casestartswith(sd->link.string, "file://")) 875 return;
847 // TODO: decode string: %XX -> char 876
848 path = sd->link.string + sizeof("file://") - 1; 877 if (link_is_url(link))
849 else 878 url = EINA_TRUE;
850 url = EINA_TRUE; 879 else if (link[0] == '/')
851 } 880 path = link;
852 else if (sd->link.string[0] == '/') 881 else if (link_is_email(link))
853 path = sd->link.string;
854 else if (link_is_email(sd->link.string))
855 email = EINA_TRUE; 882 email = EINA_TRUE;
856 883
857 if (url && casestartswith(sd->link.string, "mailto:")) 884 if (url && casestartswith(link, "mailto:"))
858 { 885 {
859 email = EINA_TRUE; 886 email = EINA_TRUE;
860 url = EINA_FALSE; 887 url = EINA_FALSE;
861 } 888 }
862 889
863 s = eina_str_escape(sd->link.string); 890 s = eina_str_escape(link);
864 if (!s) return; 891 if (!s) return;
865 if (email) 892 if (email)
866 { 893 {
@@ -888,10 +915,10 @@ _activate_link(Evas_Object *obj, Eina_Bool may_inline)
888 // locally accessible file 915 // locally accessible file
889 cmd = "xdg-open"; 916 cmd = "xdg-open";
890 917
891 escaped = ecore_file_escape_name(s); 918 escaped = ecore_file_escape_name(path);
892 if (escaped) 919 if (escaped)
893 { 920 {
894 Media_Type type = media_src_type_get(sd->link.string); 921 Media_Type type = media_src_type_get(path);
895 if (may_inline && _should_inline(obj)) 922 if (may_inline && _should_inline(obj))
896 { 923 {
897 if ((type == MEDIA_TYPE_IMG) || 924 if ((type == MEDIA_TYPE_IMG) ||
@@ -942,7 +969,7 @@ _activate_link(Evas_Object *obj, Eina_Bool may_inline)
942 escaped = ecore_file_escape_name(s); 969 escaped = ecore_file_escape_name(s);
943 if (escaped) 970 if (escaped)
944 { 971 {
945 Media_Type type = media_src_type_get(sd->link.string); 972 Media_Type type = media_src_type_get(link);
946 if (may_inline && _should_inline(obj)) 973 if (may_inline && _should_inline(obj))
947 { 974 {
948 evas_object_smart_callback_call(obj, "popup", NULL); 975 evas_object_smart_callback_call(obj, "popup", NULL);
@@ -1050,9 +1077,20 @@ _cb_ctxp_link_content_copy(void *data,
1050 size_t len; 1077 size_t len;
1051 EINA_SAFETY_ON_NULL_RETURN(sd); 1078 EINA_SAFETY_ON_NULL_RETURN(sd);
1052 1079
1053 raw_link = termio_selection_get(term, sd->link.x1, sd->link.y1, sd->link.x2, sd->link.y2, &len, EINA_FALSE); 1080 if (sd->link.id)
1081 {
1082 Term_Link *hl = &sd->pty->hl.links[sd->link.id];
1054 1083
1055 _take_selection_text(sd, ELM_SEL_TYPE_CLIPBOARD, raw_link); 1084 if (!hl->url)
1085 return;
1086 _take_selection_text(sd, ELM_SEL_TYPE_CLIPBOARD, hl->url);
1087 }
1088 else
1089 {
1090 raw_link = termio_selection_get(term, sd->link.x1, sd->link.y1, sd->link.x2, sd->link.y2, &len, EINA_FALSE);
1091
1092 _take_selection_text(sd, ELM_SEL_TYPE_CLIPBOARD, raw_link);
1093 }
1056 1094
1057 sd->ctxpopup = NULL; 1095 sd->ctxpopup = NULL;
1058 evas_object_del(obj); 1096 evas_object_del(obj);
@@ -1082,6 +1120,16 @@ _cb_link_down(void *data,
1082 Evas_Event_Mouse_Down *ev = event; 1120 Evas_Event_Mouse_Down *ev = event;
1083 Termio *sd = evas_object_smart_data_get(data); 1121 Termio *sd = evas_object_smart_data_get(data);
1084 EINA_SAFETY_ON_NULL_RETURN(sd); 1122 EINA_SAFETY_ON_NULL_RETURN(sd);
1123 Term_Link *hl = NULL;
1124
1125
1126 if (!sd->link.string && sd->link.id)
1127 {
1128 hl = &sd->pty->hl.links[sd->link.id];
1129 if (!hl->url)
1130 return;
1131 sd->link.string = eina_stringshare_add(hl->url);
1132 }
1085 1133
1086 if (ev->button == 1) 1134 if (ev->button == 1)
1087 { 1135 {
@@ -1093,7 +1141,7 @@ _cb_link_down(void *data,
1093 { 1141 {
1094 Evas_Object *ctxp; 1142 Evas_Object *ctxp;
1095 Eina_Bool absolut = EINA_FALSE; 1143 Eina_Bool absolut = EINA_FALSE;
1096 char *raw_link; 1144 const char *raw_link;
1097 size_t len; 1145 size_t len;
1098 1146
1099 if (sd->pty->selection.is_active) 1147 if (sd->pty->selection.is_active)
@@ -1121,7 +1169,20 @@ _cb_link_down(void *data,
1121 } 1169 }
1122 elm_ctxpopup_item_append(ctxp, _("Open"), NULL, _cb_ctxp_link_open, 1170 elm_ctxpopup_item_append(ctxp, _("Open"), NULL, _cb_ctxp_link_open,
1123 sd->self); 1171 sd->self);
1124 raw_link = termio_selection_get(sd->self, sd->link.x1, sd->link.y1, sd->link.x2, sd->link.y2, &len, EINA_FALSE); 1172 if (hl)
1173 {
1174 raw_link = hl->url;
1175 }
1176 else
1177 {
1178 raw_link = termio_selection_get(sd->self,
1179 sd->link.x1,
1180 sd->link.y1,
1181 sd->link.x2,
1182 sd->link.y2,
1183 &len,
1184 EINA_FALSE);
1185 }
1125 1186
1126 if (len > 0 && raw_link[0] == '/') 1187 if (len > 0 && raw_link[0] == '/')
1127 absolut = EINA_TRUE; 1188 absolut = EINA_TRUE;
@@ -1145,7 +1206,8 @@ _cb_link_down(void *data,
1145 _cb_ctxp_dismissed, sd); 1206 _cb_ctxp_dismissed, sd);
1146 evas_object_event_callback_add(ctxp, EVAS_CALLBACK_DEL, 1207 evas_object_event_callback_add(ctxp, EVAS_CALLBACK_DEL,
1147 _cb_ctxp_del, sd); 1208 _cb_ctxp_del, sd);
1148 free(raw_link); 1209 if (!hl)
1210 free((void*)raw_link);
1149 } 1211 }
1150} 1212}
1151 1213
@@ -1257,7 +1319,8 @@ _cb_link_move(void *data,
1257 Evas_Coord dx, dy; 1319 Evas_Coord dx, dy;
1258 EINA_SAFETY_ON_NULL_RETURN(sd); 1320 EINA_SAFETY_ON_NULL_RETURN(sd);
1259 1321
1260 if (!sd->link.down.down) return; 1322 if (!sd->link.down.down)
1323 return;
1261 dx = abs(ev->cur.canvas.x - sd->link.down.x); 1324 dx = abs(ev->cur.canvas.x - sd->link.down.x);
1262 dy = abs(ev->cur.canvas.y - sd->link.down.y); 1325 dy = abs(ev->cur.canvas.y - sd->link.down.y);
1263 if ((sd->config->drag_links) && 1326 if ((sd->config->drag_links) &&
@@ -1384,7 +1447,7 @@ _remove_links(Termio *sd)
1384 1447
1385 if (sd->link.string) 1448 if (sd->link.string)
1386 { 1449 {
1387 free(sd->link.string); 1450 eina_stringshare_del(sd->link.string);
1388 sd->link.string = NULL; 1451 sd->link.string = NULL;
1389 } 1452 }
1390 sd->link.x1 = -1; 1453 sd->link.x1 = -1;
@@ -2511,7 +2574,7 @@ termio_take_selection(Evas_Object *obj, Elm_Sel_Type type)
2511{ 2574{
2512 Termio *sd = evas_object_smart_data_get(obj); 2575 Termio *sd = evas_object_smart_data_get(obj);
2513 int start_x = 0, start_y = 0, end_x = 0, end_y = 0; 2576 int start_x = 0, start_y = 0, end_x = 0, end_y = 0;
2514 char *s = NULL; 2577 const char *s = NULL;
2515 size_t len = 0; 2578 size_t len = 0;
2516 2579
2517 EINA_SAFETY_ON_NULL_RETURN_VAL(sd, EINA_FALSE); 2580 EINA_SAFETY_ON_NULL_RETURN_VAL(sd, EINA_FALSE);
@@ -2533,7 +2596,7 @@ termio_take_selection(Evas_Object *obj, Elm_Sel_Type type)
2533 if (sd->link.string) 2596 if (sd->link.string)
2534 { 2597 {
2535 len = strlen(sd->link.string); 2598 len = strlen(sd->link.string);
2536 s = strndup(sd->link.string, len); 2599 s = eina_stringshare_add_length(sd->link.string, len);
2537 } 2600 }
2538 goto end; 2601 goto end;
2539 } 2602 }
@@ -2560,12 +2623,14 @@ termio_take_selection(Evas_Object *obj, Elm_Sel_Type type)
2560 } 2623 }
2561 len = eina_strbuf_length_get(sb); 2624 len = eina_strbuf_length_get(sb);
2562 s = eina_strbuf_string_steal(sb); 2625 s = eina_strbuf_string_steal(sb);
2626 s = eina_stringshare_add_length(s, len);
2563 eina_strbuf_free(sb); 2627 eina_strbuf_free(sb);
2564 } 2628 }
2565 else 2629 else
2566 { 2630 {
2567 s = termio_selection_get(obj, start_x, start_y, end_x, end_y, &len, 2631 s = termio_selection_get(obj, start_x, start_y, end_x, end_y, &len,
2568 EINA_TRUE); 2632 EINA_TRUE);
2633 s = eina_stringshare_add_length(s, len);
2569 } 2634 }
2570 2635
2571end: 2636end:
@@ -2573,7 +2638,7 @@ end:
2573 { 2638 {
2574 if ((sd->win) && (len > 0)) 2639 if ((sd->win) && (len > 0))
2575 _take_selection_text(sd, type, s); 2640 _take_selection_text(sd, type, s);
2576 free(s); 2641 eina_stringshare_del(s);
2577 return EINA_TRUE; 2642 return EINA_TRUE;
2578 } 2643 }
2579 return EINA_FALSE; 2644 return EINA_FALSE;
@@ -3711,7 +3776,8 @@ _smart_mouseover_apply(Evas_Object *obj)
3711 3776
3712 EINA_SAFETY_ON_NULL_RETURN(sd); 3777 EINA_SAFETY_ON_NULL_RETURN(sd);
3713 config = sd->config; 3778 config = sd->config;
3714 if (!config->active_links) return; 3779 if (!config->active_links)
3780 return;
3715 3781
3716 if ((sd->mouse.cx < 0) || (sd->mouse.cy < 0) || 3782 if ((sd->mouse.cx < 0) || (sd->mouse.cy < 0) ||
3717 (sd->link.suspend) || (!evas_object_focus_get(obj))) 3783 (sd->link.suspend) || (!evas_object_focus_get(obj)))
@@ -3741,8 +3807,8 @@ _smart_mouseover_apply(Evas_Object *obj)
3741 } 3807 }
3742 3808
3743 if (sd->link.string) 3809 if (sd->link.string)
3744 free(sd->link.string); 3810 eina_stringshare_del(sd->link.string);
3745 sd->link.string = s; 3811 sd->link.string = eina_stringshare_add(s);
3746 3812
3747 if ((x1 == sd->link.x1) && (y1 == sd->link.y1) && 3813 if ((x1 == sd->link.x1) && (y1 == sd->link.y1) &&
3748 (x2 == sd->link.x2) && (y2 == sd->link.y2)) 3814 (x2 == sd->link.x2) && (y2 == sd->link.y2))
@@ -5531,7 +5597,8 @@ _smart_del(Evas_Object *obj)
5531 if (sd->mouseover_delay) ecore_timer_del(sd->mouseover_delay); 5597 if (sd->mouseover_delay) ecore_timer_del(sd->mouseover_delay);
5532 if (sd->font.name) eina_stringshare_del(sd->font.name); 5598 if (sd->font.name) eina_stringshare_del(sd->font.name);
5533 if (sd->pty) termpty_free(sd->pty); 5599 if (sd->pty) termpty_free(sd->pty);
5534 if (sd->link.string) free(sd->link.string); 5600 if (sd->link.string)
5601 eina_stringshare_del(sd->link.string);
5535 if (sd->glayer) evas_object_del(sd->glayer); 5602 if (sd->glayer) evas_object_del(sd->glayer);
5536 if (sd->win) 5603 if (sd->win)
5537 evas_object_event_callback_del_full(sd->win, EVAS_CALLBACK_DEL, 5604 evas_object_event_callback_del_full(sd->win, EVAS_CALLBACK_DEL,
diff --git a/src/bin/win.c b/src/bin/win.c
index d6c4b75..5b3dd01 100644
--- a/src/bin/win.c
+++ b/src/bin/win.c
@@ -4401,9 +4401,13 @@ _cb_popup(void *data,
4401 Term *term = data; 4401 Term *term = data;
4402 const char *src = event; 4402 const char *src = event;
4403 4403
4404 if (!src) src = termio_link_get(term->termio); 4404 if (!src)
4405 if (!src) return; 4405 src = termio_link_get(term->termio);
4406 if (!src)
4407 return;
4406 _popmedia(term, src); 4408 _popmedia(term, src);
4409 if (!event)
4410 free((void*)src);
4407} 4411}
4408 4412
4409static void 4413static void
@@ -4413,9 +4417,14 @@ _cb_popup_queue(void *data,
4413{ 4417{
4414 Term *term = data; 4418 Term *term = data;
4415 const char *src = event; 4419 const char *src = event;
4416 if (!src) src = termio_link_get(term->termio); 4420
4417 if (!src) return; 4421 if (!src)
4422 src = termio_link_get(term->termio);
4423 if (!src)
4424 return;
4418 _popmedia_queue_add(term, src); 4425 _popmedia_queue_add(term, src);
4426 if (!event)
4427 free((void*)src);
4419} 4428}
4420 4429
4421static void 4430static void