2 * ion/mod_query/wedln.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
11 #include <libtu/objp.h>
12 #include <libtu/minmax.h>
13 #include <libtu/setparam.h>
14 #include <libextl/extl.h>
15 #include <libmainloop/defer.h>
16 #include <libmainloop/signal.h>
18 #include <ioncore/common.h>
19 #include <ioncore/global.h>
20 #include <ioncore/strings.h>
21 #include <ioncore/xic.h>
22 #include <ioncore/selection.h>
23 #include <ioncore/event.h>
24 #include <ioncore/regbind.h>
25 #include <ioncore/gr-util.h>
26 #include <ioncore/sizehint.h>
27 #include <ioncore/resize.h>
35 #define WEDLN_BRUSH(X) ((X)->input.brush)
38 /*{{{ Drawing primitives */
41 static int calc_text_y(WEdln
*wedln
, const WRectangle
*geom
)
45 grbrush_get_font_extents(WEDLN_BRUSH(wedln
), &fnte
);
47 return geom
->y
+geom
->h
/2-fnte
.max_height
/2+fnte
.baseline
;
51 static int wedln_draw_strsect(WEdln
*wedln
, int x
, int y
, const char *str
,
57 grbrush_set_attr(WEDLN_BRUSH(wedln
), a
);
58 grbrush_draw_string(WEDLN_BRUSH(wedln
), x
, y
, str
, len
, TRUE
);
59 grbrush_unset_attr(WEDLN_BRUSH(wedln
), a
);
61 return grbrush_get_text_width(WEDLN_BRUSH(wedln
), str
, len
);
65 static void dispu(const char* s
, int l
)
68 int c
=(unsigned char)*s
;
69 fprintf(stderr
, "%d[%c]", c
, *s
);
73 fprintf(stderr
, "\n");
77 #define DSTRSECT(LEN, A) \
79 tx+=wedln_draw_strsect(wedln, geom->x+tx, ty, \
80 str, LEN, GR_ATTR(A)); \
88 GR_DEFATTR(selection
);
93 static void init_attr()
97 GR_ALLOCATTR(inactive
);
99 GR_ALLOCATTR(selection
);
100 GR_ALLOCATTR(cursor
);
101 GR_ALLOCATTR(prompt
);
107 static void wedln_do_draw_str_box(WEdln
*wedln
, const WRectangle
*geom
,
108 const char *str
, int cursor
,
111 int len
=strlen(str
), ll
=0, ty
=0;
113 ty
=calc_text_y(wedln
, geom
);
117 DSTRSECT(mark
, normal
);
118 DSTRSECT(cursor
-mark
, selection
);
120 DSTRSECT(cursor
, normal
);
123 tx
+=wedln_draw_strsect(wedln
, geom
->x
+tx
, ty
,
124 " ", 1, GR_ATTR(cursor
));
126 ll
=str_nextoff(str
, 0);
127 DSTRSECT(ll
, cursor
);
130 DSTRSECT(cursor
, normal
);
131 ll
=str_nextoff(str
, 0);
132 DSTRSECT(ll
, cursor
);
133 DSTRSECT(mark
-cursor
-ll
, selection
);
135 DSTRSECT(len
, normal
);
141 grbrush_clear_area(WEDLN_BRUSH(wedln
), &g
);
146 static void wedln_draw_str_box(WEdln
*wedln
, const WRectangle
*geom
,
147 int vstart
, const char *str
,
148 int dstart
, int point
, int mark
)
152 /* Some fonts and Xmb/utf8 routines don't work well with dstart!=0. */
161 point
-=vstart
+dstart
;
164 tx
=grbrush_get_text_width(WEDLN_BRUSH(wedln
), str
+vstart
, dstart
);
166 grbrush_begin(WEDLN_BRUSH(wedln
), geom
,
167 GRBRUSH_AMEND
|GRBRUSH_KEEP_ATTR
|GRBRUSH_NEED_CLIP
);
169 wedln_do_draw_str_box(wedln
, geom
, str
+vstart
+dstart
, point
, mark
, tx
);
171 grbrush_end(WEDLN_BRUSH(wedln
));
175 static bool wedln_update_cursor(WEdln
*wedln
, int iw
)
178 int vstart
=wedln
->vstart
;
179 int point
=wedln
->edln
.point
;
180 int len
=wedln
->edln
.psize
;
181 const char *str
=wedln
->edln
.p
;
184 if(point
<wedln
->vstart
)
187 if(wedln
->vstart
==point
)
192 cx
=grbrush_get_text_width(WEDLN_BRUSH(wedln
), str
+vstart
,
194 cx
+=grbrush_get_text_width(WEDLN_BRUSH(wedln
), " ", 1);
196 int nxt
=str_nextoff(str
, point
);
197 cx
=grbrush_get_text_width(WEDLN_BRUSH(wedln
), str
+vstart
,
204 l
=str_nextoff(str
, vstart
);
210 ret
=(wedln
->vstart
!=vstart
);
211 wedln
->vstart
=vstart
;
220 /*{{{ Size/location calc */
223 static int get_textarea_height(WEdln
*wedln
, bool with_spacing
)
227 if(WEDLN_BRUSH(wedln
)!=NULL
)
228 mod_query_get_minimum_extents(WEDLN_BRUSH(wedln
), with_spacing
, &w
, &h
);
234 enum{G_NORESET
, G_MAX
, G_CURRENT
};
237 static void get_geom(WEdln
*wedln
, int mode
, WRectangle
*geom
)
240 *geom
=wedln
->input
.last_fp
.g
;
241 else if(mode
==G_CURRENT
)
242 *geom
=REGION_GEOM(wedln
);
246 static void get_completions_geom(WEdln
*wedln
, int mode
, WRectangle
*geom
)
248 get_geom(wedln
, mode
, geom
);
252 geom
->h
-=get_textarea_height(wedln
, TRUE
);
258 static void get_outer_geom(WEdln
*wedln
, int mode
, WRectangle
*geom
)
262 get_geom(wedln
, mode
, geom
);
266 th
=get_textarea_height(wedln
, FALSE
);
273 static void get_inner_geom(WEdln
*wedln
, int mode
, WRectangle
*geom
)
277 grbrush_get_border_widths(WEDLN_BRUSH(wedln
), &bdw
);
279 get_outer_geom(wedln
, mode
, geom
);
282 geom
->w
-=bdw
.left
+bdw
.right
;
284 geom
->h
-=bdw
.top
+bdw
.bottom
;
285 geom
->w
=maxof(0, geom
->w
);
286 geom
->h
=maxof(0, geom
->h
);
290 static void get_textarea_geom(WEdln
*wedln
, int mode
, WRectangle
*geom
)
292 get_inner_geom(wedln
, mode
, geom
);
293 geom
->x
+=wedln
->prompt_w
;
294 geom
->w
=maxof(0, geom
->w
- wedln
->prompt_w
- wedln
->info_w
);
298 static void wedln_calc_size(WEdln
*wedln
, WRectangle
*geom
)
302 WRectangle max_geom
=*geom
, tageom
;
304 if(WEDLN_BRUSH(wedln
)==NULL
)
307 if(wedln
->prompt
!=NULL
){
308 wedln
->prompt_w
=grbrush_get_text_width(WEDLN_BRUSH(wedln
),
313 if(wedln
->info
!=NULL
){
314 wedln
->info_w
=grbrush_get_text_width(WEDLN_BRUSH(wedln
),
319 th
=get_textarea_height(wedln
, wedln
->compl_list
.strs
!=NULL
);
321 if(wedln
->compl_list
.strs
==NULL
){
322 if(max_geom
.h
<th
|| !(wedln
->input
.last_fp
.mode
®ION_FIT_BOUNDS
))
329 get_completions_geom(wedln
, G_MAX
, &g
);
331 fit_listing(WEDLN_BRUSH(wedln
), &g
, &(wedln
->compl_list
));
333 grbrush_get_border_widths(WEDLN_BRUSH(wedln
), &bdw
);
335 h
=wedln
->compl_list
.toth
;
336 th
+=bdw
.top
+bdw
.bottom
;
338 if(h
+th
>max_geom
.h
|| !(wedln
->input
.last_fp
.mode
®ION_FIT_BOUNDS
))
344 geom
->y
=max_geom
.y
+max_geom
.h
-geom
->h
;
348 get_textarea_geom(wedln
, G_NORESET
, &tageom
);
349 wedln_update_cursor(wedln
, tageom
.w
);
353 void wedln_size_hints(WEdln
*wedln
, WSizeHints
*hints_ret
)
357 if(WEDLN_BRUSH(wedln
)!=NULL
){
358 mod_query_get_minimum_extents(WEDLN_BRUSH(wedln
), FALSE
, &w
, &h
);
359 w
+=wedln
->prompt_w
+wedln
->info_w
;
360 w
+=grbrush_get_text_width(WEDLN_BRUSH(wedln
), "xxxxxxxxxx", 10);
363 hints_ret
->min_set
=TRUE
;
364 hints_ret
->min_width
=w
;
365 hints_ret
->min_height
=h
;
375 void wedln_draw_completions(WEdln
*wedln
, int mode
)
379 if(wedln
->compl_list
.strs
!=NULL
&& WEDLN_BRUSH(wedln
)!=NULL
){
380 get_completions_geom(wedln
, G_CURRENT
, &geom
);
382 draw_listing(WEDLN_BRUSH(wedln
), &geom
, &(wedln
->compl_list
),
383 mode
, GR_ATTR(selection
));
388 void wedln_draw_textarea(WEdln
*wedln
)
393 if(WEDLN_BRUSH(wedln
)==NULL
)
396 get_outer_geom(wedln
, G_CURRENT
, &geom
);
398 /*grbrush_begin(WEDLN_BRUSH(wedln), &geom, GRBRUSH_AMEND);*/
400 grbrush_draw_border(WEDLN_BRUSH(wedln
), &geom
);
402 get_inner_geom(wedln
, G_CURRENT
, &geom
);
404 ty
=calc_text_y(wedln
, &geom
);
406 grbrush_set_attr(WEDLN_BRUSH(wedln
), GR_ATTR(prompt
));
408 if(wedln
->prompt
!=NULL
){
409 grbrush_draw_string(WEDLN_BRUSH(wedln
), geom
.x
, ty
,
410 wedln
->prompt
, wedln
->prompt_len
, TRUE
);
413 if(wedln
->info
!=NULL
){
414 int x
=geom
.x
+geom
.w
-wedln
->info_w
;
416 grbrush_set_attr(WEDLN_BRUSH(wedln
), GR_ATTR(info
));
417 grbrush_draw_string(WEDLN_BRUSH(wedln
), x
, ty
,
418 wedln
->info
, wedln
->info_len
, TRUE
);
419 grbrush_unset_attr(WEDLN_BRUSH(wedln
), GR_ATTR(info
));
422 grbrush_unset_attr(WEDLN_BRUSH(wedln
), GR_ATTR(prompt
));
424 get_textarea_geom(wedln
, G_CURRENT
, &geom
);
426 wedln_draw_str_box(wedln
, &geom
, wedln
->vstart
, wedln
->edln
.p
, 0,
427 wedln
->edln
.point
, wedln
->edln
.mark
);
429 /*grbrush_end(WEDLN_BRUSH(wedln));*/
433 static void wedln_draw_(WEdln
*wedln
, bool complete
, bool completions
)
436 int f
=(complete
? 0 : GRBRUSH_NO_CLEAR_OK
);
438 if(WEDLN_BRUSH(wedln
)==NULL
)
441 get_geom(wedln
, G_CURRENT
, &g
);
443 grbrush_begin(WEDLN_BRUSH(wedln
), &g
, f
);
445 grbrush_set_attr(WEDLN_BRUSH(wedln
), REGION_IS_ACTIVE(wedln
)
447 : GR_ATTR(inactive
));
450 wedln_draw_completions(wedln
, LISTING_DRAW_ALL
);
452 wedln_draw_textarea(wedln
);
454 grbrush_end(WEDLN_BRUSH(wedln
));
458 void wedln_draw(WEdln
*wedln
, bool complete
)
460 wedln_draw_(wedln
, complete
, TRUE
);
469 static void wedln_set_info(WEdln
*wedln
, const char *info
)
473 if(wedln
->info
!=NULL
){
481 wedln
->info
=scat3(" [", info
, "]");
482 if(wedln
->info
!=NULL
){
483 wedln
->info_len
=strlen(wedln
->info
);
484 if(WEDLN_BRUSH(wedln
)!=NULL
){
485 wedln
->info_w
=grbrush_get_text_width(WEDLN_BRUSH(wedln
),
492 get_textarea_geom(wedln
, G_CURRENT
, &tageom
);
493 wedln_update_cursor(wedln
, tageom
.w
);
495 wedln_draw_(wedln
, FALSE
, FALSE
);
505 static void wedln_show_completions(WEdln
*wedln
, char **strs
, int nstrs
,
508 int w
=REGION_GEOM(wedln
).w
;
509 int h
=REGION_GEOM(wedln
).h
;
511 if(WEDLN_BRUSH(wedln
)==NULL
)
514 setup_listing(&(wedln
->compl_list
), strs
, nstrs
, FALSE
);
515 wedln
->compl_list
.selected_str
=selected
;
517 input_refit((WInput
*)wedln
);
518 if(w
==REGION_GEOM(wedln
).w
&& h
==REGION_GEOM(wedln
).h
)
519 wedln_draw_completions(wedln
, LISTING_DRAW_COMPLETE
);
523 void wedln_hide_completions(WEdln
*wedln
)
525 if(wedln
->compl_list
.strs
!=NULL
){
526 deinit_listing(&(wedln
->compl_list
));
527 input_refit((WInput
*)wedln
);
532 void wedln_scrollup_completions(WEdln
*wedln
)
534 if(wedln
->compl_list
.strs
==NULL
)
536 if(scrollup_listing(&(wedln
->compl_list
)))
537 wedln_draw_completions(wedln
, LISTING_DRAW_COMPLETE
);
541 void wedln_scrolldown_completions(WEdln
*wedln
)
543 if(wedln
->compl_list
.strs
==NULL
)
545 if(scrolldown_listing(&(wedln
->compl_list
)))
546 wedln_draw_completions(wedln
, LISTING_DRAW_COMPLETE
);
550 static int update_nocompl
=0;
553 static void free_completions(char **ptr
, int i
)
564 bool wedln_do_set_completions(WEdln
*wedln
, char **ptr
, int n
,
565 char *beg
, char *end
, int cycle
,
570 if(wedln
->compl_beg
!=NULL
)
571 free(wedln
->compl_beg
);
573 if(wedln
->compl_end
!=NULL
)
574 free(wedln
->compl_end
);
576 wedln
->compl_beg
=beg
;
577 wedln
->compl_end
=end
;
578 wedln
->compl_current_id
=-1;
580 n
=edln_do_completions(&(wedln
->edln
), ptr
, n
, beg
, end
,
581 !mod_query_config
.autoshowcompl
, nosort
);
583 if(mod_query_config
.autoshowcompl
&& n
>0 && cycle
!=0){
585 sel
=(cycle
>0 ? 0 : n
-1);
586 edln_set_completion(&(wedln
->edln
), ptr
[sel
], beg
, end
);
590 if(n
>1 || (mod_query_config
.autoshowcompl
&& n
>0)){
591 wedln_show_completions(wedln
, ptr
, n
, sel
);
595 free_completions(ptr
, n
);
601 void wedln_set_completions(WEdln
*wedln
, ExtlTab completions
, int cycle
)
604 char **ptr
=NULL
, *beg
=NULL
, *end
=NULL
, *p
=NULL
;
606 n
=extl_table_get_n(completions
);
609 wedln_hide_completions(wedln
);
613 ptr
=ALLOC_N(char*, n
);
618 if(!extl_table_geti_s(completions
, i
+1, &p
)){
624 extl_table_gets_s(completions
, "common_beg", &beg
);
625 extl_table_gets_s(completions
, "common_end", &end
);
627 if(!wedln_do_set_completions(wedln
, ptr
, n
, beg
, end
, cycle
, FALSE
))
628 wedln_hide_completions(wedln
);
633 wedln_hide_completions(wedln
);
634 free_completions(ptr
, i
);
638 static void wedln_do_select_completion(WEdln
*wedln
, int n
)
640 bool redraw
=listing_select(&(wedln
->compl_list
), n
);
641 wedln_draw_completions(wedln
, redraw
);
644 edln_set_completion(&(wedln
->edln
), wedln
->compl_list
.strs
[n
],
645 wedln
->compl_beg
, wedln
->compl_end
);
651 static ExtlExportedFn
*sc_safe_fns
[]={
652 (ExtlExportedFn
*)&complproxy_set_completions
,
657 static ExtlSafelist sc_safelist
=EXTL_SAFELIST_INIT(sc_safe_fns
);
660 static int wedln_alloc_compl_id(WEdln
*wedln
)
662 int id
=wedln
->compl_waiting_id
+1;
663 wedln
->compl_waiting_id
=maxof(0, wedln
->compl_waiting_id
+1);
667 static bool wedln_do_call_completor(WEdln
*wedln
, int id
, int cycle
)
669 if(wedln
->compl_history_mode
){
673 wedln
->compl_waiting_id
=id
;
675 n
=edln_history_matches(&wedln
->edln
, &h
);
678 wedln_hide_completions(wedln
);
682 if(wedln_do_set_completions(wedln
, h
, n
, NULL
, NULL
, cycle
, TRUE
)){
683 wedln
->compl_current_id
=id
;
689 const char *p
=wedln
->edln
.p
;
690 int point
=wedln
->edln
.point
;
691 WComplProxy
*proxy
=create_complproxy(wedln
, id
, cycle
);
696 /* Set Lua-side to own the proxy: it gets freed by Lua's GC */
697 ((Obj
*)proxy
)->flags
|=OBJ_EXTL_OWNED
;
704 extl_protect(&sc_safelist
);
705 extl_call(wedln
->completor
, "osi", NULL
, proxy
, p
, point
);
706 extl_unprotect(&sc_safelist
);
713 static void timed_complete(WTimer
*UNUSED(tmr
), Obj
*obj
)
715 WEdln
*wedln
=(WEdln
*)obj
;
718 int id
=wedln
->compl_timed_id
;
719 wedln
->compl_timed_id
=-1;
720 if(id
==wedln
->compl_waiting_id
&& id
>=0)
721 wedln_do_call_completor((WEdln
*)obj
, id
, FALSE
);
727 * Select next completion.
730 bool wedln_next_completion(WEdln
*wedln
)
734 if(wedln
->compl_current_id
!=wedln
->compl_waiting_id
)
737 if(wedln
->compl_list
.nstrs
<=0)
740 if(wedln
->compl_list
.selected_str
<0 ||
741 wedln
->compl_list
.selected_str
+1>=wedln
->compl_list
.nstrs
){
744 n
=wedln
->compl_list
.selected_str
+1;
747 if(n
!=wedln
->compl_list
.selected_str
)
748 wedln_do_select_completion(wedln
, n
);
755 * Select previous completion.
758 bool wedln_prev_completion(WEdln
*wedln
)
762 if(wedln
->compl_current_id
!=wedln
->compl_waiting_id
)
765 if(wedln
->compl_list
.nstrs
<=0)
768 if(wedln
->compl_list
.selected_str
<=0){
769 n
=wedln
->compl_list
.nstrs
-1;
771 n
=wedln
->compl_list
.selected_str
-1;
774 if(n
!=wedln
->compl_list
.selected_str
)
775 wedln_do_select_completion(wedln
, n
);
782 * Call completion handler with the text between the beginning of line and
783 * current cursor position, or select next/previous completion from list if in
784 * auto-show-completions mode and \var{cycle} is set to \codestr{next} or
785 * \codestr{prev}, respectively.
786 * The \var{mode} may be \codestr{history} or \codestr{normal}. If it is
787 * not set, the previous mode is used. Normally next entry is not cycled to
788 * despite the setting of \var{cycle} if mode switch occurs. To override
789 * this, use \codestr{next-always} and \codestr{prev-always} for \var{cycle}.
792 void wedln_complete(WEdln
*wedln
, const char *cycle
, const char *mode
)
798 if(strcmp(mode
, "history")==0){
799 valid
=wedln
->compl_history_mode
;
800 wedln
->compl_history_mode
=TRUE
;
801 }else if(strcmp(mode
, "normal")==0){
802 valid
=!wedln
->compl_history_mode
;
803 wedln
->compl_history_mode
=FALSE
;
806 wedln_set_info(wedln
,
807 (wedln
->compl_history_mode
814 if((valid
&& strcmp(cycle
, "next")==0) ||
815 strcmp(cycle
, "next-always")==0){
817 }else if((valid
&& strcmp(cycle
, "prev")==0) ||
818 strcmp(cycle
, "prev-always")==0){
823 if(valid
&& cyclei
!=0 && mod_query_config
.autoshowcompl
&&
824 wedln
->compl_list
.nstrs
>0){
826 wedln_next_completion(wedln
);
828 wedln_prev_completion(wedln
);
830 int oldid
=wedln
->compl_waiting_id
;
832 if(!wedln_do_call_completor(wedln
, wedln_alloc_compl_id(wedln
),
834 wedln
->compl_waiting_id
=oldid
;
841 * Get history completion mode.
844 bool wedln_is_histcompl(WEdln
*wedln
)
846 return wedln
->compl_history_mode
;
853 /*{{{ Update handler */
856 static void wedln_update_handler(WEdln
*wedln
, int from
, int flags
)
860 if(WEDLN_BRUSH(wedln
)==NULL
)
863 get_textarea_geom(wedln
, G_CURRENT
, &geom
);
865 if(flags
&EDLN_UPDATE_NEW
)
868 if(flags
&EDLN_UPDATE_MOVED
){
869 if(wedln_update_cursor(wedln
, geom
.w
))
873 from
=maxof(0, from
-wedln
->vstart
);
875 wedln_draw_str_box(wedln
, &geom
, wedln
->vstart
, wedln
->edln
.p
, from
,
876 wedln
->edln
.point
, wedln
->edln
.mark
);
878 if(update_nocompl
==0 &&
879 mod_query_config
.autoshowcompl
&&
880 flags
&EDLN_UPDATE_CHANGED
){
881 wedln
->compl_current_id
=-1; /* invalidate */
882 if(wedln
->autoshowcompl_timer
==NULL
)
883 wedln
->autoshowcompl_timer
=create_timer();
884 if(wedln
->autoshowcompl_timer
!=NULL
){
885 wedln
->compl_timed_id
=wedln_alloc_compl_id(wedln
);
886 timer_set(wedln
->autoshowcompl_timer
,
887 mod_query_config
.autoshowcompl_delay
,
888 timed_complete
, (Obj
*)wedln
);
897 /*{{{ Init, deinit and config update */
900 static bool wedln_init_prompt(WEdln
*wedln
, const char *prompt
)
911 wedln
->prompt_len
=strlen(p
);
922 static bool wedln_init(WEdln
*wedln
, WWindow
*par
, const WFitParams
*fp
,
923 WEdlnCreateParams
*params
)
929 if(!wedln_init_prompt(wedln
, params
->prompt
))
932 if(!edln_init(&(wedln
->edln
), params
->dflt
)){
937 wedln
->handler
=extl_fn_none();
938 wedln
->completor
=extl_fn_none();
940 wedln
->edln
.uiptr
=wedln
;
941 wedln
->edln
.ui_update
=(EdlnUpdateHandler
*)wedln_update_handler
;
943 wedln
->autoshowcompl_timer
=NULL
;
945 init_listing(&(wedln
->compl_list
));
947 wedln
->compl_waiting_id
=-1;
948 wedln
->compl_current_id
=-1;
949 wedln
->compl_timed_id
=-1;
950 wedln
->compl_beg
=NULL
;
951 wedln
->compl_end
=NULL
;
952 wedln
->compl_tab
=FALSE
;
953 wedln
->compl_history_mode
=FALSE
;
959 wedln
->cycle_bindmap
=NULL
;
961 if(!input_init((WInput
*)wedln
, par
, fp
)){
962 edln_deinit(&(wedln
->edln
));
967 window_create_xic(&wedln
->input
.win
);
969 wedln
->handler
=extl_ref_fn(params
->handler
);
970 wedln
->completor
=extl_ref_fn(params
->completor
);
972 region_add_bindmap((WRegion
*)wedln
, mod_query_wedln_bindmap
);
978 WEdln
*create_wedln(WWindow
*par
, const WFitParams
*fp
,
979 WEdlnCreateParams
*params
)
981 CREATEOBJ_IMPL(WEdln
, wedln
, (p
, par
, fp
, params
));
985 static void wedln_deinit(WEdln
*wedln
)
987 if(wedln
->prompt
!=NULL
)
990 if(wedln
->info
!=NULL
)
993 if(wedln
->compl_beg
!=NULL
)
994 free(wedln
->compl_beg
);
996 if(wedln
->compl_end
!=NULL
)
997 free(wedln
->compl_end
);
999 if(wedln
->compl_list
.strs
!=NULL
)
1000 deinit_listing(&(wedln
->compl_list
));
1002 if(wedln
->autoshowcompl_timer
!=NULL
)
1003 destroy_obj((Obj
*)wedln
->autoshowcompl_timer
);
1005 if(wedln
->cycle_bindmap
!=NULL
)
1006 bindmap_destroy(wedln
->cycle_bindmap
);
1008 extl_unref_fn(wedln
->completor
);
1009 extl_unref_fn(wedln
->handler
);
1011 edln_deinit(&(wedln
->edln
));
1012 input_deinit((WInput
*)wedln
);
1016 static void wedln_do_finish(WEdln
*wedln
)
1021 handler
=wedln
->handler
;
1022 wedln
->handler
=extl_fn_none();
1023 p
=edln_finish(&(wedln
->edln
));
1025 region_rqdispose((WRegion
*)wedln
);
1028 extl_call(handler
, "s", NULL
, p
);
1031 extl_unref_fn(handler
);
1036 * Close \var{wedln} and call any handlers.
1039 void wedln_finish(WEdln
*wedln
)
1041 mainloop_defer_action((Obj
*)wedln
, (WDeferredAction
*)wedln_do_finish
);
1052 * Request selection from application holding such.
1054 * Note that this function is asynchronous; the selection will not
1055 * actually be inserted before Ion receives it. This will be no
1056 * earlier than Ion return to its main loop.
1059 void wedln_paste(WEdln
*wedln
)
1061 ioncore_request_selection_for(wedln
->input
.win
.win
);
1065 void wedln_insstr(WEdln
*wedln
, const char *buf
, size_t n
)
1067 edln_insstr_n(&(wedln
->edln
), buf
, n
, TRUE
, TRUE
);
1071 static const char *wedln_style(WEdln
*UNUSED(wedln
))
1073 return "input-edln";
1080 /*{{{ Dynamic function table and class implementation */
1083 static DynFunTab wedln_dynfuntab
[]={
1084 {window_draw
, wedln_draw
},
1085 {input_calc_size
, wedln_calc_size
},
1086 {input_scrollup
, wedln_scrollup_completions
},
1087 {input_scrolldown
, wedln_scrolldown_completions
},
1088 {window_insstr
, wedln_insstr
},
1089 {(DynFun
*)input_style
, (DynFun
*)wedln_style
},
1090 {region_size_hints
, wedln_size_hints
},
1096 IMPLCLASS(WEdln
, WInput
, wedln_deinit
, wedln_dynfuntab
);