44import sys
55
66from functools import partial
7+ from types import SimpleNamespace
78
89import cairo
910
@@ -98,37 +99,48 @@ def __init__(self, font):
9899 self .grids = {}
99100 self .g = None
100101
101- def create_drawing_area (self , handle ):
102- self .g = Grid ()
103- self .g .handle = handle
104- self .g ._resize_timer_id = None
102+ def get_grid (self , handle ):
103+ if handle in self .grids :
104+ return self .grids [handle ]
105+ g = Grid ()
106+ g .handle = handle
107+ g ._pending = [0 , 0 , 0 ]
108+ g ._screen = None
105109 drawing_area = Gtk .DrawingArea ()
106- drawing_area .connect ('draw' , partial (self ._gtk_draw , self .g ))
110+ drawing_area .connect ('draw' , partial (self ._gtk_draw , g ))
111+ g ._pango_context = drawing_area .create_pango_context ()
112+ g ._drawing_area = drawing_area
113+ g ._window = None
114+ g .options = None
115+ self .grids [handle ] = g
116+ return g
117+
118+ def create_window (self , handle ):
119+ g = self .get_grid (handle )
120+ g ._resize_timer_id = None
107121 window = Gtk .Window ()
108- window .add (drawing_area )
122+ layout = Gtk .Fixed ()
123+ window .add (layout )
124+ layout .put (g ._drawing_area ,0 ,0 )
109125 window .set_events (window .get_events () |
110126 Gdk .EventMask .BUTTON_PRESS_MASK |
111127 Gdk .EventMask .BUTTON_RELEASE_MASK |
112128 Gdk .EventMask .POINTER_MOTION_MASK |
113129 Gdk .EventMask .SCROLL_MASK )
114- window .connect ('configure-event' , partial (self ._gtk_configure , self . g ))
130+ window .connect ('configure-event' , partial (self ._gtk_configure , g ))
115131 window .connect ('delete-event' , self ._gtk_quit )
116132 window .connect ('key-press-event' , self ._gtk_key )
117133 window .connect ('key-release-event' , self ._gtk_key_release )
118- window .connect ('button-press-event' , partial (self ._gtk_button_press , self . g ))
119- window .connect ('button-release-event' , partial (self ._gtk_button_release , self . g ))
120- window .connect ('motion-notify-event' , partial (self ._gtk_motion_notify , self . g ))
121- window .connect ('scroll-event' , partial (self ._gtk_scroll , self . g ))
134+ window .connect ('button-press-event' , partial (self ._gtk_button_press , g ))
135+ window .connect ('button-release-event' , partial (self ._gtk_button_release , g ))
136+ window .connect ('motion-notify-event' , partial (self ._gtk_motion_notify , g ))
137+ window .connect ('scroll-event' , partial (self ._gtk_scroll , g ))
122138 window .connect ('focus-in-event' , self ._gtk_focus_in )
123139 window .connect ('focus-out-event' , self ._gtk_focus_out )
124140 window .show_all ()
125- self .g ._pango_context = drawing_area .create_pango_context ()
126- self .g ._drawing_area = drawing_area
127- self .g ._window = window
128- self .g ._pending = [0 , 0 , 0 ]
129- self .g ._screen = None
141+ g ._window = window
142+ g ._layout = layout
130143
131- self .grids [handle ] = self .g
132144
133145
134146 def start (self , bridge ):
@@ -138,7 +150,10 @@ def start(self, bridge):
138150 im_context .set_use_preedit (False ) # TODO: preedit at cursor position
139151 im_context .connect ('commit' , self ._gtk_input )
140152 self ._im_context = im_context
141- self .create_drawing_area (1 )
153+ self .create_window (1 )
154+ self .g = self .get_grid (1 )
155+ self ._window = self .g ._window
156+ self ._layout = self .g ._layout
142157 self ._bridge = bridge
143158 Gtk .main ()
144159
@@ -165,19 +180,57 @@ def wrapper():
165180 def _screen_invalid (self ):
166181 self .g ._drawing_area .queue_draw ()
167182
183+ def _nvim_float_info (self , win , handle , width , height , options ):
184+ g = self .get_grid (handle )
185+ g .nvim_win = win
186+ g .options = SimpleNamespace (** options )
187+ self .configure_float (g )
188+
189+ def _nvim_float_close (self , win , handle ):
190+ g = self .get_grid (handle )
191+
192+ if g ._window is not None :
193+ g ._layout .remove (g ._drawing_area )
194+ g ._window .destroy ()
195+ elif g ._drawing_area .get_parent () == self ._layout :
196+ self ._layout .remove (g ._drawing_area )
197+
198+ def configure_float (self , g ):
199+ if g .options .standalone :
200+ if not g ._window :
201+ if g ._drawing_area .get_parent () == self ._layout :
202+ self ._layout .remove (g ._drawing_area )
203+ self .create_window (g .handle )
204+ else :
205+ if g ._window is not None :
206+ g ._layout .remove (g ._drawing_area )
207+ g ._window .destroy ()
208+ # this is ugly, but I'm too lazy to refactor nvim_resize
209+ # to fit the flow of information
210+ if g ._drawing_area .get_parent () != self ._layout :
211+ self ._layout .add (g ._drawing_area )
212+ g ._drawing_area .show ()
213+ if g ._screen is not None :
214+ x = g .options .x * self ._cell_pixel_width
215+ y = g .options .y * self ._cell_pixel_height
216+ w ,h = g .pixel_size
217+ if len (g .options .anchor ) >= 2 :
218+ if g .options .anchor [0 ] == 'S' :
219+ y -= h
220+ if g .options .anchor [1 ] == 'E' :
221+ x -= w
222+ self ._layout .move (g ._drawing_area ,x ,y )
223+
168224 def _nvim_grid_cursor_goto (self , handle , row , col ):
169225 print ("I" ,handle ,file = sys .stderr )
170226 self ._curgrid = handle
171- if handle not in self .grids :
172- self .create_drawing_area (handle )
173- self .g = self .grids [handle ]
227+ self .g = self .get_grid (handle )
174228 self ._screen = self .g ._screen
175229 if self ._screen is not None :
176230 # TODO: this should really be asserted on the nvim side
177231 row , col = min (row , self ._screen .rows ), min (col , self ._screen .columns )
178232 self ._screen .cursor_goto (row ,col )
179- self ._drawing_area = self .g ._drawing_area
180- self ._window = self .g ._window
233+
181234
182235
183236 def _nvim_resize (self , columns , rows ):
@@ -207,7 +260,13 @@ def _nvim_resize(self, columns, rows):
207260 self ._cell_pixel_height = cell_pixel_height
208261 self .g ._screen = Screen (columns , rows )
209262 self ._screen = self .g ._screen
210- self .g ._window .resize (pixel_width , pixel_height )
263+ self .g ._drawing_area .set_size_request (pixel_width , pixel_height )
264+ self .g .pixel_size = pixel_width , pixel_height
265+ if self .g .options is not None :
266+ self .configure_float (self .g )
267+
268+ if self .g ._window is not None :
269+ self .g ._window .resize (pixel_width , pixel_height )
211270
212271 def _nvim_clear (self ):
213272 self ._clear_region (self ._screen .top , self ._screen .bot + 1 ,
@@ -498,6 +557,9 @@ def _get_coords(self, row, col):
498557 def _flush (self ,g = None ):
499558 gs = [g ] if g is not None else self .grids .values ()
500559 for g in gs :
560+ if g ._screen is None :
561+ continue
562+
501563 row , startcol , endcol = g ._pending
502564 g ._pending [0 ] = g ._screen .row
503565 g ._pending [1 ] = g ._screen .col
0 commit comments