@@ -66,6 +66,7 @@ popup.parent = parent
6666--- @class snowcap.popup.PopupHandle
6767--- @field id integer Popup ' s id.
6868--- @field private _update fun (msg : any )
69+ --- @field private _operate fun (oper : snowcap.widget.operation.Operation )
6970local PopupHandle = {}
7071
7172--- Convert a PopupHandle into a Popup's ParentHandle
7980--- @package
8081--- @param id integer
8182--- @param update fun ( msg : any )
83+ --- @param operate fun ( oper : snowcap.widget.operation.Operation )
8284--- @return snowcap.popup.PopupHandle
83- function popup_handle .new (id , update )
85+ function popup_handle .new (id , update , operate )
8486 --- @type snowcap.popup.PopupHandle
8587 local self = {
8688 id = id ,
8789 _update = update ,
90+ _operate = operate
8891 }
8992 setmetatable (self , { __index = PopupHandle })
9093 return self
@@ -265,29 +268,30 @@ function popup.new_widget(args)
265268
266269 local popup_id = response .popup_id --[[ @as integer]]
267270
271+ local sender , receiver = require (" snowcap.util.channel" ).spsc ()
272+
268273 --- @type fun ( msg : any ?)
269274 local update_on_msg = function (msg )
270275 if msg ~= nil then
271- args .program :update (msg )
272- end
273-
274- --- @diagnostic disable-next-line : redefined-local
275- local _ , err = client :snowcap_popup_v1_PopupService_RequestView ({
276- popup_id = popup_id ,
277- })
278-
279- if err then
280- log .error (err )
276+ sender :send ({
277+ message = msg
278+ })
279+ else
280+ sender :send ({
281+ redraw = {}
282+ })
281283 end
282284 end
283285
284- local handle = popup_handle .new (popup_id , update_on_msg )
285-
286286 --- @type fun ( oper : snowcap.widget.operation.Operation )
287- local forward_operation = function (oper )
288- handle :operate (oper )
287+ local operate_surface = function (oper )
288+ sender :send ({
289+ operation = oper ,
290+ })
289291 end
290292
293+ local handle = popup_handle .new (popup_id , update_on_msg , operate_surface )
294+
291295 --- @type fun (): snowcap.signal.HandlerPolicy
292296 local close_surface = function ()
293297 handle :close ()
@@ -297,7 +301,7 @@ function popup.new_widget(args)
297301
298302 args .program :connect (widget_signal .redraw_needed , update_on_msg )
299303 args .program :connect (widget_signal .send_message , update_on_msg )
300- args .program :connect (widget_signal .operation , forward_operation )
304+ args .program :connect (widget_signal .operation , operate_surface )
301305 args .program :connect (widget_signal .request_close , close_surface )
302306
303307 args .program :event ({
@@ -307,73 +311,116 @@ function popup.new_widget(args)
307311 err = client :snowcap_popup_v1_PopupService_GetPopupEvents ({
308312 popup_id = popup_id ,
309313 }, function (response ) --- @diagnostic disable-line : redefined-local
310- response .popup_events = response .popup_events or {}
311-
312- for _ , popup_event in ipairs (response .popup_events ) do
313- local focus = popup_event .focus --[[ @as snowcap.popup.FocusEvent]]
314- --- @type snowcap.widget.SurfaceEvent ?
315- local event = nil
316-
317- if focus == focus_event .GAINED then
318- event = {
319- focus_gained = {},
320- }
321- elseif focus == focus_event .LOST then
322- event = {
323- focus_lost = {},
324- }
325- end
326-
327- if event then
328- args .program :event (event )
329- end
330- end
331-
332- --- @diagnostic disable-next-line : redefined-local
333- local _ , err = client :snowcap_popup_v1_PopupService_RequestView ({
334- popup_id = popup_id ,
314+ sender :send ({
315+ popup_events = response .popup_events or {}
335316 })
336-
337- if err then
338- log .error (err )
339- end
340317 end )
341318
342319 err = client :snowcap_widget_v1_WidgetService_GetWidgetEvents ({
343320 popup_id = popup_id ,
344321 }, function (response ) --- @diagnostic disable-line : redefined-local
345- for _ , event in ipairs (response .widget_events ) do
346- local msg = widget ._message_from_event (callbacks , event )
347-
348- if msg then
349- local ok , update_err = pcall (function ()
350- args .program :update (msg )
351- end )
322+ sender :send ({
323+ widget_events = response .widget_events or {}
324+ })
325+ end )
352326
353- if not ok then
354- log .error (update_err )
327+ client .loop :wrap (function ()
328+ local pending_operations = {}
329+
330+ local msg = receiver :recv ()
331+ while msg do
332+ local update_view = false
333+
334+ if msg .widget_events then
335+ for _ , event in ipairs (msg .widget_events ) do
336+ local message = widget ._message_from_event (callbacks , event )
337+
338+ if message then
339+ local ok , update_err = pcall (function ()
340+ args .program :update (message )
341+ end )
342+ if not ok then
343+ log .error (update_err )
344+ end
345+ end
346+ end
347+ update_view = true
348+ elseif msg .message then
349+ args .program :update (msg .message )
350+ elseif msg .operation then
351+ table.insert (pending_operations , msg .operation )
352+ elseif msg .popup_events then
353+ for _ , popup_event in ipairs (msg .popup_events ) do
354+ if popup_event .closing ~= nil then
355+ goto main_loop_break
356+ end
357+
358+ local focus = popup_event .focus --[[ @as snowcap.popup.FocusEvent]]
359+ --- @type snowcap.widget.SurfaceEvent ?
360+ local event = nil
361+
362+ if focus == focus_event .GAINED then
363+ event = {
364+ focus_gained = {},
365+ }
366+ elseif focus == focus_event .LOST then
367+ event = {
368+ focus_lost = {},
369+ }
370+ end
371+
372+ if event then
373+ args .program :event (event )
374+ end
355375 end
356376 end
357- end
358377
359- --- @diagnostic disable-next-line : redefined-local
360- local widget_def = args .program :view () or widget .row ({ children = {} })
361- callbacks = {}
378+ if not update_view then
379+ --- @diagnostic disable-next-line : redefined-local
380+ local _ , err = client :snowcap_popup_v1_PopupService_RequestView ({
381+ popup_id = popup_id ,
382+ })
362383
363- widget ._traverse_widget_tree (widget_def , callbacks , widget ._collect_callbacks )
384+ if err then
385+ log .error (err )
386+ end
387+ else
388+ --- @diagnostic disable-next-line : redefined-local
389+ local widget_def = args .program :view () or widget .row ({ children = {} })
390+ callbacks = {}
364391
365- --- @diagnostic disable-next-line : redefined-local
366- local _ , err = client :snowcap_popup_v1_PopupService_UpdatePopup ({
367- popup_id = popup_id ,
368- widget_def = widget .widget_def_into_api (widget_def ),
369- })
392+ widget ._traverse_widget_tree (widget_def , callbacks , widget ._collect_callbacks )
393+
394+ --- @diagnostic disable-next-line : redefined-local
395+ local _ , err = client :snowcap_popup_v1_PopupService_UpdatePopup ({
396+ popup_id = popup_id ,
397+ widget_def = widget .widget_def_into_api (widget_def ),
398+ })
399+
400+ if err then
401+ log .error (err )
402+ end
403+
404+ for _ , oper in pairs (pending_operations ) do
405+ --- @diagnostic disable-next-line : redefined-local
406+ local _ , err = client :snowcap_popup_v1_PopupService_OperatePopup ({
407+ popup_id = popup_id ,
408+ operation = require (" snowcap.widget.operation" )._to_api (oper ), --- @diagnostic disable-line : invisible
409+ })
410+
411+ if err then
412+ log .error (err )
413+ end
414+ end
415+ pending_operations = {}
416+ end
370417
371- if err then
372- log .error (err )
418+ msg = receiver :recv ()
373419 end
374- end , function ()
420+ :: main_loop_break::
421+
375422 args .program :event ({
376- closing = {},
423+ closing = {}
377424 })
378425 end )
379426
429476--- Sends an `Operation` to this popup.
430477--- @param operation snowcap.widget.operation.Operation
431478function PopupHandle :operate (operation )
432- local _ , err = client :snowcap_popup_v1_PopupService_OperatePopup ({
433- popup_id = self .id ,
434- operation = require (" snowcap.widget.operation" )._to_api (operation ), --- @diagnostic disable-line : invisible
435- })
436-
437- if err then
438- log .error (err )
439- end
479+ self ._operate (operation )
440480end
441481
442482--- PopupHandle:popup parameters.
0 commit comments