Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file lTerm_running_impl.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194openLwtopenLTerm_geomtypet=LTerm_widget_base_impl.tclasstoplevel=LTerm_toplevel_impl.toplevel(* for focus cycling *)letrecfind_focusablewidget=ifwidget#can_focusthenSomewidgetelsefind_focusable_in_listwidget#childrenandfind_focusable_in_list=function|[]->None|child::rest->matchfind_focusablechildwith|Some_assome->some|None->find_focusable_in_listrest(* Mouse support *)letrecpickcoordwidget=ifnot(LTerm_geom.in_rectwidget#allocationcoord)thenNoneelseletf()=ifwidget#can_focusthenSome(widget,coord)elseNoneinletw=(* search children *)List.fold_left(functionNone->pickcoord|Some(w,c)->(fun_->Some(w,c)))Nonewidget#childreninifw=Nonethenf()elsew(* An event for the main loop. *)type'aevent=|Valueof'a(* A value from the waiter thread. *)|EventofLTerm_event.t(* A event from the terminal. *)letlambda_termrc=Filename.concatLTerm_resources.home".lambda-termrc"letfile_existsfile=Lwt.catch(fun()->Lwt_unix.accessfile[Unix.R_OK]>>=fun()->returntrue)(function|Unix.Unix_error_->returnfalse|exn->Lwt.failexn)letapply_resources?cacheload_resourcesresources_filewidget=ifload_resourcesthenfile_existsresources_file>>=funhas_resources->matchhas_resourceswith|true->LTerm_resources.loadresources_file>>=funresources->widget#set_resourcesresources;beginmatchcachewith|None->()|Somec->c:=resourcesend;return()|false->return()elsereturn()letref_focuswidget=ref(matchfind_focusablewidgetwith|Somew->w|None->widget)letrun_modalterm?save_state?(load_resources=true)?(resources_file=lambda_termrc)push_eventpop_eventwidgetwaiter=letwidget=(widget:>t)inletresources_cache=refLTerm_resources.emptyinapply_resources~cache:resources_cacheload_resourcesresources_filewidget>>=fun()->(* The currently focused widget. *)letfocused=ref_focuswidgetin(* Create a toplevel widget. *)lettoplevel=newtoplevelfocusedwidgetin(* Drawing function for toplevels. *)letdraw_toplevel=ref(fun()->())in(* Size for toplevels. *)letsize_ref=ref{row1=0;col1=0;row2=0;col2=0}inletlayers=ref[toplevel]inletfocuses=ref[focused]in(* Layer event handlers. *)letpush_layerw=letnew_focus=ref_focuswinletnew_top=newtoplevelnew_focuswinnew_top#set_queue_draw!draw_toplevel;new_top#set_allocation!size_ref;focuses:=new_focus::!focuses;layers:=new_top::!layers;new_top#set_resources!resources_cache;new_top#queue_drawinletpop_layer()=match!layerswith|[_]->failwith"Trying to destroy the only existing layer."|_::tl->layers:=tl;focuses:=List.tl!focuses;(List.hd!layers)#queue_draw|[]->failwith"Internal error: no idea how it happened."in(* Arm layer event handlers. *)toplevel#arm_layer_handlerspush_eventpush_layerpop_eventpop_layer;letdrawuimatrix=letctx=LTerm_draw.contextmatrix(LTerm_ui.sizeui)inLTerm_draw.clearctx;(* Draw the layers starting from the bottom *)letlayers_rev=List.rev!layersinletfocuses_rev=List.rev!focusesinList.iter2(funtopfocus->top#drawctx!focus)layers_revfocuses_rev;letcurrent_focus=List.hd!focusesinmatch!current_focus#cursor_positionwith|Somecoord->letrect=!current_focus#allocationinLTerm_ui.set_cursor_visibleuitrue;LTerm_ui.set_cursor_positionui{row=rect.row1+coord.row;col=rect.col1+coord.col}|None->LTerm_ui.set_cursor_visibleuifalseinLTerm_ui.createterm?save_statedraw>>=funui->draw_toplevel:=(fun()->LTerm_ui.drawui);toplevel#set_queue_draw!draw_toplevel;letsize=LTerm_ui.sizeuiinsize_ref:={!size_refwithrow2=size.rows;col2=size.cols};toplevel#set_allocation!size_ref;(* Loop handling events. *)letwaiter=waiter>|=funx->Valuexinletrecloop()=letthread=LTerm_ui.waitui>|=funx->Eventxinchoose[thread;waiter]>>=function|Event(LTerm_event.Resizesize)->size_ref:={!size_refwithrow2=size.rows;col2=size.cols};List.iter(funtop->top#set_allocation!size_ref)!layers;loop()(* left button mouse click *)|Event((LTerm_event.Mousem)asev)whenLTerm_mouse.(m.button=Button1)->beginletpicked=pickLTerm_mouse.(coordm)(toplevel:>t)inmatchpickedwith|Some_->(* move focus and send it the event *)toplevel#move_focus_topicked;!(List.hd!focuses)#send_eventev;loop()|None->(* nothing got focus, so drop the event *)loop()end|Eventev->!(List.hd!focuses)#send_eventev;loop()|Valuevalue->cancelthread;returnvalueinLwt.finalizeloop(fun()->LTerm_ui.quitui)letrunterm?save_state?load_resources?resources_filewidgetwaiter=run_modalterm?save_state?load_resources?resources_fileLwt_react.E.neverLwt_react.E.neverwidgetwaiterletprepare_simple_run()=letwaiter,wakener=wait()inletpush_ev,push_ev_send=Lwt_react.E.create()inletpop_ev,pop_ev_send=Lwt_react.E.create()inletexit=wakeupwakenerinletpush_layerw=fun()->push_ev_send(w:>t)inletpop_layer=pop_ev_sendinletdo_runw=Lazy.forceLTerm.stdout>>=funterm->run_modaltermpush_evpop_evwwaiterin(do_run,push_layer,pop_layer,exit)