Skip to content
This repository was archived by the owner on Jun 30, 2023. It is now read-only.

Commit 58170c9

Browse files
committed
implement proper floating windows
1 parent 3fd2e4b commit 58170c9

File tree

1 file changed

+86
-24
lines changed

1 file changed

+86
-24
lines changed

neovim_gui/gtk_ui.py

Lines changed: 86 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import sys
55

66
from functools import partial
7+
from types import SimpleNamespace
78

89
import 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

Comments
 (0)