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
, const WRectangle
*geom
,
52 int x
, int y
, const char *str
, int len
,
58 grbrush_set_attr(WEDLN_BRUSH(wedln
), a
);
59 grbrush_draw_string(WEDLN_BRUSH(wedln
), x
, y
, str
, len
, TRUE
);
60 grbrush_unset_attr(WEDLN_BRUSH(wedln
), a
);
62 return grbrush_get_text_width(WEDLN_BRUSH(wedln
), str
, len
);
66 static void dispu(const char* s
, int l
)
69 int c
=(unsigned char)*s
;
70 fprintf(stderr
, "%d[%c]", c
, *s
);
74 fprintf(stderr
, "\n");
78 #define DSTRSECT(LEN, A) \
80 tx+=wedln_draw_strsect(wedln, geom, geom->x+tx, ty, \
81 str, LEN, GR_ATTR(A)); \
89 GR_DEFATTR(selection
);
94 static void init_attr()
98 GR_ALLOCATTR(inactive
);
100 GR_ALLOCATTR(selection
);
101 GR_ALLOCATTR(cursor
);
102 GR_ALLOCATTR(prompt
);
108 static void wedln_do_draw_str_box(WEdln
*wedln
, const WRectangle
*geom
,
109 const char *str
, int cursor
,
112 int len
=strlen(str
), ll
=0, ty
=0;
114 ty
=calc_text_y(wedln
, geom
);
118 DSTRSECT(mark
, normal
);
119 DSTRSECT(cursor
-mark
, selection
);
121 DSTRSECT(cursor
, normal
);
124 tx
+=wedln_draw_strsect(wedln
, geom
, geom
->x
+tx
, ty
,
125 " ", 1, GR_ATTR(cursor
));
127 ll
=str_nextoff(str
, 0);
128 DSTRSECT(ll
, cursor
);
131 DSTRSECT(cursor
, normal
);
132 ll
=str_nextoff(str
, 0);
133 DSTRSECT(ll
, cursor
);
134 DSTRSECT(mark
-cursor
-ll
, selection
);
136 DSTRSECT(len
, normal
);
142 grbrush_clear_area(WEDLN_BRUSH(wedln
), &g
);
147 static void wedln_draw_str_box(WEdln
*wedln
, const WRectangle
*geom
,
148 int vstart
, const char *str
,
149 int dstart
, int point
, int mark
)
153 /* Some fonts and Xmb/utf8 routines don't work well with dstart!=0. */
162 point
-=vstart
+dstart
;
165 tx
=grbrush_get_text_width(WEDLN_BRUSH(wedln
), str
+vstart
, dstart
);
167 grbrush_begin(WEDLN_BRUSH(wedln
), geom
,
168 GRBRUSH_AMEND
|GRBRUSH_KEEP_ATTR
|GRBRUSH_NEED_CLIP
);
170 wedln_do_draw_str_box(wedln
, geom
, str
+vstart
+dstart
, point
, mark
, tx
);
172 grbrush_end(WEDLN_BRUSH(wedln
));
176 static bool wedln_update_cursor(WEdln
*wedln
, int iw
)
179 int vstart
=wedln
->vstart
;
180 int point
=wedln
->edln
.point
;
181 int len
=wedln
->edln
.psize
;
182 int mark
=wedln
->edln
.mark
;
183 const char *str
=wedln
->edln
.p
;
186 if(point
<wedln
->vstart
)
189 if(wedln
->vstart
==point
)
194 cx
=grbrush_get_text_width(WEDLN_BRUSH(wedln
), str
+vstart
,
196 cx
+=grbrush_get_text_width(WEDLN_BRUSH(wedln
), " ", 1);
198 int nxt
=str_nextoff(str
, point
);
199 cx
=grbrush_get_text_width(WEDLN_BRUSH(wedln
), str
+vstart
,
206 l
=str_nextoff(str
, vstart
);
212 ret
=(wedln
->vstart
!=vstart
);
213 wedln
->vstart
=vstart
;
222 /*{{{ Size/location calc */
225 static int get_textarea_height(WEdln
*wedln
, bool with_spacing
)
229 if(WEDLN_BRUSH(wedln
)!=NULL
)
230 mod_query_get_minimum_extents(WEDLN_BRUSH(wedln
), with_spacing
, &w
, &h
);
236 enum{G_NORESET
, G_MAX
, G_CURRENT
};
239 static void get_geom(WEdln
*wedln
, int mode
, WRectangle
*geom
)
242 *geom
=wedln
->input
.last_fp
.g
;
243 else if(mode
==G_CURRENT
)
244 *geom
=REGION_GEOM(wedln
);
248 static void get_completions_geom(WEdln
*wedln
, int mode
, WRectangle
*geom
)
250 get_geom(wedln
, mode
, geom
);
254 geom
->h
-=get_textarea_height(wedln
, TRUE
);
260 static void get_outer_geom(WEdln
*wedln
, int mode
, WRectangle
*geom
)
264 get_geom(wedln
, mode
, geom
);
268 th
=get_textarea_height(wedln
, FALSE
);
275 static void get_inner_geom(WEdln
*wedln
, int mode
, WRectangle
*geom
)
279 grbrush_get_border_widths(WEDLN_BRUSH(wedln
), &bdw
);
281 get_outer_geom(wedln
, mode
, geom
);
284 geom
->w
-=bdw
.left
+bdw
.right
;
286 geom
->h
-=bdw
.top
+bdw
.bottom
;
287 geom
->w
=maxof(0, geom
->w
);
288 geom
->h
=maxof(0, geom
->h
);
292 static void get_textarea_geom(WEdln
*wedln
, int mode
, WRectangle
*geom
)
294 get_inner_geom(wedln
, mode
, geom
);
295 geom
->x
+=wedln
->prompt_w
;
296 geom
->w
=maxof(0, geom
->w
- wedln
->prompt_w
- wedln
->info_w
);
300 static void wedln_calc_size(WEdln
*wedln
, WRectangle
*geom
)
304 WRectangle max_geom
=*geom
, tageom
;
306 if(WEDLN_BRUSH(wedln
)==NULL
)
309 if(wedln
->prompt
!=NULL
){
310 wedln
->prompt_w
=grbrush_get_text_width(WEDLN_BRUSH(wedln
),
315 if(wedln
->info
!=NULL
){
316 wedln
->info_w
=grbrush_get_text_width(WEDLN_BRUSH(wedln
),
321 th
=get_textarea_height(wedln
, wedln
->compl_list
.strs
!=NULL
);
323 if(wedln
->compl_list
.strs
==NULL
){
324 if(max_geom
.h
<th
|| !(wedln
->input
.last_fp
.mode
®ION_FIT_BOUNDS
))
331 get_completions_geom(wedln
, G_MAX
, &g
);
333 fit_listing(WEDLN_BRUSH(wedln
), &g
, &(wedln
->compl_list
));
335 grbrush_get_border_widths(WEDLN_BRUSH(wedln
), &bdw
);
337 h
=wedln
->compl_list
.toth
;
338 th
+=bdw
.top
+bdw
.bottom
;
340 if(h
+th
>max_geom
.h
|| !(wedln
->input
.last_fp
.mode
®ION_FIT_BOUNDS
))
346 geom
->y
=max_geom
.y
+max_geom
.h
-geom
->h
;
350 get_textarea_geom(wedln
, G_NORESET
, &tageom
);
351 wedln_update_cursor(wedln
, tageom
.w
);
355 void wedln_size_hints(WEdln
*wedln
, WSizeHints
*hints_ret
)
359 if(WEDLN_BRUSH(wedln
)!=NULL
){
360 mod_query_get_minimum_extents(WEDLN_BRUSH(wedln
), FALSE
, &w
, &h
);
361 w
+=wedln
->prompt_w
+wedln
->info_w
;
362 w
+=grbrush_get_text_width(WEDLN_BRUSH(wedln
), "xxxxxxxxxx", 10);
365 hints_ret
->min_set
=TRUE
;
366 hints_ret
->min_width
=w
;
367 hints_ret
->min_height
=h
;
377 void wedln_draw_completions(WEdln
*wedln
, int mode
)
381 if(wedln
->compl_list
.strs
!=NULL
&& WEDLN_BRUSH(wedln
)!=NULL
){
382 get_completions_geom(wedln
, G_CURRENT
, &geom
);
384 draw_listing(WEDLN_BRUSH(wedln
), &geom
, &(wedln
->compl_list
),
385 mode
, GR_ATTR(selection
));
390 void wedln_draw_textarea(WEdln
*wedln
)
395 if(WEDLN_BRUSH(wedln
)==NULL
)
398 get_outer_geom(wedln
, G_CURRENT
, &geom
);
400 /*grbrush_begin(WEDLN_BRUSH(wedln), &geom, GRBRUSH_AMEND);*/
402 grbrush_draw_border(WEDLN_BRUSH(wedln
), &geom
);
404 get_inner_geom(wedln
, G_CURRENT
, &geom
);
406 ty
=calc_text_y(wedln
, &geom
);
408 grbrush_set_attr(WEDLN_BRUSH(wedln
), GR_ATTR(prompt
));
410 if(wedln
->prompt
!=NULL
){
411 grbrush_draw_string(WEDLN_BRUSH(wedln
), geom
.x
, ty
,
412 wedln
->prompt
, wedln
->prompt_len
, TRUE
);
415 if(wedln
->info
!=NULL
){
416 int x
=geom
.x
+geom
.w
-wedln
->info_w
;
418 grbrush_set_attr(WEDLN_BRUSH(wedln
), GR_ATTR(info
));
419 grbrush_draw_string(WEDLN_BRUSH(wedln
), x
, ty
,
420 wedln
->info
, wedln
->info_len
, TRUE
);
421 grbrush_unset_attr(WEDLN_BRUSH(wedln
), GR_ATTR(info
));
424 grbrush_unset_attr(WEDLN_BRUSH(wedln
), GR_ATTR(prompt
));
426 get_textarea_geom(wedln
, G_CURRENT
, &geom
);
428 wedln_draw_str_box(wedln
, &geom
, wedln
->vstart
, wedln
->edln
.p
, 0,
429 wedln
->edln
.point
, wedln
->edln
.mark
);
431 /*grbrush_end(WEDLN_BRUSH(wedln));*/
435 static void wedln_draw_(WEdln
*wedln
, bool complete
, bool completions
)
438 int f
=(complete
? 0 : GRBRUSH_NO_CLEAR_OK
);
440 if(WEDLN_BRUSH(wedln
)==NULL
)
443 get_geom(wedln
, G_CURRENT
, &g
);
445 grbrush_begin(WEDLN_BRUSH(wedln
), &g
, f
);
447 grbrush_set_attr(WEDLN_BRUSH(wedln
), REGION_IS_ACTIVE(wedln
)
449 : GR_ATTR(inactive
));
452 wedln_draw_completions(wedln
, LISTING_DRAW_ALL
);
454 wedln_draw_textarea(wedln
);
456 grbrush_end(WEDLN_BRUSH(wedln
));
460 void wedln_draw(WEdln
*wedln
, bool complete
)
462 wedln_draw_(wedln
, complete
, TRUE
);
471 static void wedln_set_info(WEdln
*wedln
, const char *info
)
476 if(wedln
->info
!=NULL
){
484 wedln
->info
=scat3(" [", info
, "]");
485 if(wedln
->info
!=NULL
){
486 wedln
->info_len
=strlen(wedln
->info
);
487 if(WEDLN_BRUSH(wedln
)!=NULL
){
488 wedln
->info_w
=grbrush_get_text_width(WEDLN_BRUSH(wedln
),
495 get_textarea_geom(wedln
, G_CURRENT
, &tageom
);
496 wedln_update_cursor(wedln
, tageom
.w
);
498 wedln_draw_(wedln
, FALSE
, FALSE
);
508 static void wedln_show_completions(WEdln
*wedln
, char **strs
, int nstrs
,
511 int w
=REGION_GEOM(wedln
).w
;
512 int h
=REGION_GEOM(wedln
).h
;
514 if(WEDLN_BRUSH(wedln
)==NULL
)
517 setup_listing(&(wedln
->compl_list
), strs
, nstrs
, FALSE
);
518 wedln
->compl_list
.selected_str
=selected
;
520 input_refit((WInput
*)wedln
);
521 if(w
==REGION_GEOM(wedln
).w
&& h
==REGION_GEOM(wedln
).h
)
522 wedln_draw_completions(wedln
, LISTING_DRAW_COMPLETE
);
526 void wedln_hide_completions(WEdln
*wedln
)
528 if(wedln
->compl_list
.strs
!=NULL
){
529 deinit_listing(&(wedln
->compl_list
));
530 input_refit((WInput
*)wedln
);
535 void wedln_scrollup_completions(WEdln
*wedln
)
537 if(wedln
->compl_list
.strs
==NULL
)
539 if(scrollup_listing(&(wedln
->compl_list
)))
540 wedln_draw_completions(wedln
, LISTING_DRAW_COMPLETE
);
544 void wedln_scrolldown_completions(WEdln
*wedln
)
546 if(wedln
->compl_list
.strs
==NULL
)
548 if(scrolldown_listing(&(wedln
->compl_list
)))
549 wedln_draw_completions(wedln
, LISTING_DRAW_COMPLETE
);
553 static int update_nocompl
=0;
556 static void free_completions(char **ptr
, int i
)
567 bool wedln_do_set_completions(WEdln
*wedln
, char **ptr
, int n
,
568 char *beg
, char *end
, int cycle
,
573 if(wedln
->compl_beg
!=NULL
)
574 free(wedln
->compl_beg
);
576 if(wedln
->compl_end
!=NULL
)
577 free(wedln
->compl_end
);
579 wedln
->compl_beg
=beg
;
580 wedln
->compl_end
=end
;
581 wedln
->compl_current_id
=-1;
583 n
=edln_do_completions(&(wedln
->edln
), ptr
, n
, beg
, end
,
584 !mod_query_config
.autoshowcompl
, nosort
);
586 if(mod_query_config
.autoshowcompl
&& n
>0 && cycle
!=0){
588 sel
=(cycle
>0 ? 0 : n
-1);
589 edln_set_completion(&(wedln
->edln
), ptr
[sel
], beg
, end
);
593 if(n
>1 || (mod_query_config
.autoshowcompl
&& n
>0)){
594 wedln_show_completions(wedln
, ptr
, n
, sel
);
598 free_completions(ptr
, n
);
604 void wedln_set_completions(WEdln
*wedln
, ExtlTab completions
, int cycle
)
607 char **ptr
=NULL
, *beg
=NULL
, *end
=NULL
, *p
=NULL
;
609 n
=extl_table_get_n(completions
);
612 wedln_hide_completions(wedln
);
616 ptr
=ALLOC_N(char*, n
);
621 if(!extl_table_geti_s(completions
, i
+1, &p
)){
627 extl_table_gets_s(completions
, "common_beg", &beg
);
628 extl_table_gets_s(completions
, "common_end", &end
);
630 if(!wedln_do_set_completions(wedln
, ptr
, n
, beg
, end
, cycle
, FALSE
))
631 wedln_hide_completions(wedln
);
636 wedln_hide_completions(wedln
);
637 free_completions(ptr
, i
);
641 static void wedln_do_select_completion(WEdln
*wedln
, int n
)
643 bool redraw
=listing_select(&(wedln
->compl_list
), n
);
644 wedln_draw_completions(wedln
, redraw
);
647 edln_set_completion(&(wedln
->edln
), wedln
->compl_list
.strs
[n
],
648 wedln
->compl_beg
, wedln
->compl_end
);
654 static ExtlExportedFn
*sc_safe_fns
[]={
655 (ExtlExportedFn
*)&complproxy_set_completions
,
660 static ExtlSafelist sc_safelist
=EXTL_SAFELIST_INIT(sc_safe_fns
);
663 static int wedln_alloc_compl_id(WEdln
*wedln
)
665 int id
=wedln
->compl_waiting_id
+1;
666 wedln
->compl_waiting_id
=maxof(0, wedln
->compl_waiting_id
+1);
670 static bool wedln_do_call_completor(WEdln
*wedln
, int id
, int cycle
)
672 if(wedln
->compl_history_mode
){
676 wedln
->compl_waiting_id
=id
;
678 n
=edln_history_matches(&wedln
->edln
, &h
);
681 wedln_hide_completions(wedln
);
685 if(wedln_do_set_completions(wedln
, h
, n
, NULL
, NULL
, cycle
, TRUE
)){
686 wedln
->compl_current_id
=id
;
692 const char *p
=wedln
->edln
.p
;
693 int point
=wedln
->edln
.point
;
694 WComplProxy
*proxy
=create_complproxy(wedln
, id
, cycle
);
699 /* Set Lua-side to own the proxy: it gets freed by Lua's GC */
700 ((Obj
*)proxy
)->flags
|=OBJ_EXTL_OWNED
;
707 extl_protect(&sc_safelist
);
708 extl_call(wedln
->completor
, "osi", NULL
, proxy
, p
, point
);
709 extl_unprotect(&sc_safelist
);
716 static void timed_complete(WTimer
*tmr
, Obj
*obj
)
718 WEdln
*wedln
=(WEdln
*)obj
;
721 int id
=wedln
->compl_timed_id
;
722 wedln
->compl_timed_id
=-1;
723 if(id
==wedln
->compl_waiting_id
&& id
>=0)
724 wedln_do_call_completor((WEdln
*)obj
, id
, FALSE
);
730 * Select next completion.
733 bool wedln_next_completion(WEdln
*wedln
)
737 if(wedln
->compl_current_id
!=wedln
->compl_waiting_id
)
740 if(wedln
->compl_list
.nstrs
<=0)
743 if(wedln
->compl_list
.selected_str
<0 ||
744 wedln
->compl_list
.selected_str
+1>=wedln
->compl_list
.nstrs
){
747 n
=wedln
->compl_list
.selected_str
+1;
750 if(n
!=wedln
->compl_list
.selected_str
)
751 wedln_do_select_completion(wedln
, n
);
758 * Select previous completion.
761 bool wedln_prev_completion(WEdln
*wedln
)
765 if(wedln
->compl_current_id
!=wedln
->compl_waiting_id
)
768 if(wedln
->compl_list
.nstrs
<=0)
771 if(wedln
->compl_list
.selected_str
<=0){
772 n
=wedln
->compl_list
.nstrs
-1;
774 n
=wedln
->compl_list
.selected_str
-1;
777 if(n
!=wedln
->compl_list
.selected_str
)
778 wedln_do_select_completion(wedln
, n
);
785 * Call completion handler with the text between the beginning of line and
786 * current cursor position, or select next/previous completion from list if in
787 * auto-show-completions mode and \var{cycle} is set to \codestr{next} or
788 * \codestr{prev}, respectively.
789 * The \var{mode} may be \codestr{history} or \codestr{normal}. If it is
790 * not set, the previous mode is used. Normally next entry is not cycled to
791 * despite the setting of \var{cycle} if mode switch occurs. To override
792 * this, use \codestr{next-always} and \codestr{prev-always} for \var{cycle}.
795 void wedln_complete(WEdln
*wedln
, const char *cycle
, const char *mode
)
801 if(strcmp(mode
, "history")==0){
802 valid
=wedln
->compl_history_mode
;
803 wedln
->compl_history_mode
=TRUE
;
804 }else if(strcmp(mode
, "normal")==0){
805 valid
=!wedln
->compl_history_mode
;
806 wedln
->compl_history_mode
=FALSE
;
809 wedln_set_info(wedln
,
810 (wedln
->compl_history_mode
817 if((valid
&& strcmp(cycle
, "next")==0) ||
818 strcmp(cycle
, "next-always")==0){
820 }else if((valid
&& strcmp(cycle
, "prev")==0) ||
821 strcmp(cycle
, "prev-always")==0){
826 if(valid
&& cyclei
!=0 && mod_query_config
.autoshowcompl
&&
827 wedln
->compl_list
.nstrs
>0){
829 wedln_next_completion(wedln
);
831 wedln_prev_completion(wedln
);
833 int oldid
=wedln
->compl_waiting_id
;
835 if(!wedln_do_call_completor(wedln
, wedln_alloc_compl_id(wedln
),
837 wedln
->compl_waiting_id
=oldid
;
844 * Get history completion mode.
847 bool wedln_is_histcompl(WEdln
*wedln
)
849 return wedln
->compl_history_mode
;
856 /*{{{ Update handler */
859 static void wedln_update_handler(WEdln
*wedln
, int from
, int flags
)
863 if(WEDLN_BRUSH(wedln
)==NULL
)
866 get_textarea_geom(wedln
, G_CURRENT
, &geom
);
868 if(flags
&EDLN_UPDATE_NEW
)
871 if(flags
&EDLN_UPDATE_MOVED
){
872 if(wedln_update_cursor(wedln
, geom
.w
))
876 from
=maxof(0, from
-wedln
->vstart
);
878 wedln_draw_str_box(wedln
, &geom
, wedln
->vstart
, wedln
->edln
.p
, from
,
879 wedln
->edln
.point
, wedln
->edln
.mark
);
881 if(update_nocompl
==0 &&
882 mod_query_config
.autoshowcompl
&&
883 flags
&EDLN_UPDATE_CHANGED
){
884 wedln
->compl_current_id
=-1; /* invalidate */
885 if(wedln
->autoshowcompl_timer
==NULL
)
886 wedln
->autoshowcompl_timer
=create_timer();
887 if(wedln
->autoshowcompl_timer
!=NULL
){
888 wedln
->compl_timed_id
=wedln_alloc_compl_id(wedln
);
889 timer_set(wedln
->autoshowcompl_timer
,
890 mod_query_config
.autoshowcompl_delay
,
891 timed_complete
, (Obj
*)wedln
);
900 /*{{{ Init, deinit and config update */
903 static bool wedln_init_prompt(WEdln
*wedln
, const char *prompt
)
914 wedln
->prompt_len
=strlen(p
);
925 static bool wedln_init(WEdln
*wedln
, WWindow
*par
, const WFitParams
*fp
,
926 WEdlnCreateParams
*params
)
932 if(!wedln_init_prompt(wedln
, params
->prompt
))
935 if(!edln_init(&(wedln
->edln
), params
->dflt
)){
940 wedln
->handler
=extl_fn_none();
941 wedln
->completor
=extl_fn_none();
943 wedln
->edln
.uiptr
=wedln
;
944 wedln
->edln
.ui_update
=(EdlnUpdateHandler
*)wedln_update_handler
;
946 wedln
->autoshowcompl_timer
=NULL
;
948 init_listing(&(wedln
->compl_list
));
950 wedln
->compl_waiting_id
=-1;
951 wedln
->compl_current_id
=-1;
952 wedln
->compl_timed_id
=-1;
953 wedln
->compl_beg
=NULL
;
954 wedln
->compl_end
=NULL
;
955 wedln
->compl_tab
=FALSE
;
956 wedln
->compl_history_mode
=FALSE
;
962 wedln
->cycle_bindmap
=NULL
;
964 if(!input_init((WInput
*)wedln
, par
, fp
)){
965 edln_deinit(&(wedln
->edln
));
970 window_create_xic(&wedln
->input
.win
);
972 wedln
->handler
=extl_ref_fn(params
->handler
);
973 wedln
->completor
=extl_ref_fn(params
->completor
);
975 region_add_bindmap((WRegion
*)wedln
, mod_query_wedln_bindmap
);
981 WEdln
*create_wedln(WWindow
*par
, const WFitParams
*fp
,
982 WEdlnCreateParams
*params
)
984 CREATEOBJ_IMPL(WEdln
, wedln
, (p
, par
, fp
, params
));
988 static void wedln_deinit(WEdln
*wedln
)
990 if(wedln
->prompt
!=NULL
)
993 if(wedln
->info
!=NULL
)
996 if(wedln
->compl_beg
!=NULL
)
997 free(wedln
->compl_beg
);
999 if(wedln
->compl_end
!=NULL
)
1000 free(wedln
->compl_end
);
1002 if(wedln
->compl_list
.strs
!=NULL
)
1003 deinit_listing(&(wedln
->compl_list
));
1005 if(wedln
->autoshowcompl_timer
!=NULL
)
1006 destroy_obj((Obj
*)wedln
->autoshowcompl_timer
);
1008 if(wedln
->cycle_bindmap
!=NULL
)
1009 bindmap_destroy(wedln
->cycle_bindmap
);
1011 extl_unref_fn(wedln
->completor
);
1012 extl_unref_fn(wedln
->handler
);
1014 edln_deinit(&(wedln
->edln
));
1015 input_deinit((WInput
*)wedln
);
1019 static void wedln_do_finish(WEdln
*wedln
)
1024 handler
=wedln
->handler
;
1025 wedln
->handler
=extl_fn_none();
1026 p
=edln_finish(&(wedln
->edln
));
1028 region_rqdispose((WRegion
*)wedln
);
1031 extl_call(handler
, "s", NULL
, p
);
1034 extl_unref_fn(handler
);
1039 * Close \var{wedln} and call any handlers.
1042 void wedln_finish(WEdln
*wedln
)
1044 mainloop_defer_action((Obj
*)wedln
, (WDeferredAction
*)wedln_do_finish
);
1055 * Request selection from application holding such.
1057 * Note that this function is asynchronous; the selection will not
1058 * actually be inserted before Ion receives it. This will be no
1059 * earlier than Ion return to its main loop.
1062 void wedln_paste(WEdln
*wedln
)
1064 ioncore_request_selection_for(wedln
->input
.win
.win
);
1068 void wedln_insstr(WEdln
*wedln
, const char *buf
, size_t n
)
1070 edln_insstr_n(&(wedln
->edln
), buf
, n
, TRUE
, TRUE
);
1074 static const char *wedln_style(WEdln
*wedln
)
1076 return "input-edln";
1083 /*{{{ Dynamic function table and class implementation */
1086 static DynFunTab wedln_dynfuntab
[]={
1087 {window_draw
, wedln_draw
},
1088 {input_calc_size
, wedln_calc_size
},
1089 {input_scrollup
, wedln_scrollup_completions
},
1090 {input_scrolldown
, wedln_scrolldown_completions
},
1091 {window_insstr
, wedln_insstr
},
1092 {(DynFun
*)input_style
, (DynFun
*)wedln_style
},
1093 {region_size_hints
, wedln_size_hints
},
1099 IMPLCLASS(WEdln
, WInput
, wedln_deinit
, wedln_dynfuntab
);