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

Commit

Permalink
implement proper floating windows
Browse files Browse the repository at this point in the history
  • Loading branch information
bfredl committed Jan 7, 2018
1 parent 97f263e commit 6b54183
Showing 1 changed file with 86 additions and 24 deletions.
110 changes: 86 additions & 24 deletions neovim_gui/gtk_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import sys

from functools import partial
from types import SimpleNamespace

import cairo

Expand Down Expand Up @@ -98,37 +99,48 @@ def __init__(self, font):
self.grids = {}
self.g = None

def create_drawing_area(self, handle):
self.g = Grid()
self.g.handle = handle
self.g._resize_timer_id = None
def get_grid(self, handle):
if handle in self.grids:
return self.grids[handle]
g = Grid()
g.handle = handle
g._pending = [0, 0, 0]
g._screen = None
drawing_area = Gtk.DrawingArea()
drawing_area.connect('draw', partial(self._gtk_draw, self.g))
drawing_area.connect('draw', partial(self._gtk_draw, g))
g._pango_context = drawing_area.create_pango_context()
g._drawing_area = drawing_area
g._window = None
g.options = None
self.grids[handle] = g
return g

def create_window(self, handle):
g = self.get_grid(handle)
g._resize_timer_id = None
window = Gtk.Window()
window.add(drawing_area)
layout = Gtk.Fixed()
window.add(layout)
layout.put(g._drawing_area,0,0)
window.set_events(window.get_events() |
Gdk.EventMask.BUTTON_PRESS_MASK |
Gdk.EventMask.BUTTON_RELEASE_MASK |
Gdk.EventMask.POINTER_MOTION_MASK |
Gdk.EventMask.SCROLL_MASK)
window.connect('configure-event', partial(self._gtk_configure, self.g))
window.connect('configure-event', partial(self._gtk_configure, g))
window.connect('delete-event', self._gtk_quit)
window.connect('key-press-event', self._gtk_key)
window.connect('key-release-event', self._gtk_key_release)
window.connect('button-press-event', partial(self._gtk_button_press, self.g))
window.connect('button-release-event', partial(self._gtk_button_release, self.g))
window.connect('motion-notify-event', partial(self._gtk_motion_notify, self.g))
window.connect('scroll-event', partial(self._gtk_scroll, self.g))
window.connect('button-press-event', partial(self._gtk_button_press, g))
window.connect('button-release-event', partial(self._gtk_button_release, g))
window.connect('motion-notify-event', partial(self._gtk_motion_notify, g))
window.connect('scroll-event', partial(self._gtk_scroll, g))
window.connect('focus-in-event', self._gtk_focus_in)
window.connect('focus-out-event', self._gtk_focus_out)
window.show_all()
self.g._pango_context = drawing_area.create_pango_context()
self.g._drawing_area = drawing_area
self.g._window = window
self.g._pending = [0, 0, 0]
self.g._screen = None
g._window = window
g._layout = layout

self.grids[handle] = self.g


def start(self, bridge):
Expand All @@ -138,7 +150,10 @@ def start(self, bridge):
im_context.set_use_preedit(False) # TODO: preedit at cursor position
im_context.connect('commit', self._gtk_input)
self._im_context = im_context
self.create_drawing_area(1)
self.create_window(1)
self.g = self.get_grid(1)
self._window = self.g._window
self._layout = self.g._layout
self._bridge = bridge
Gtk.main()

Expand All @@ -165,19 +180,57 @@ def wrapper():
def _screen_invalid(self):
self.g._drawing_area.queue_draw()

def _nvim_float_info(self, win, handle, width, height, options):
g = self.get_grid(handle)
g.nvim_win = win
g.options = SimpleNamespace(**options)
self.configure_float(g)

def _nvim_float_close(self, win, handle):
g = self.get_grid(handle)

if g._window is not None:
g._layout.remove(g._drawing_area)
g._window.destroy()
elif g._drawing_area.get_parent() == self._layout:
self._layout.remove(g._drawing_area)

def configure_float(self, g):
if g.options.standalone:
if not g._window:
if g._drawing_area.get_parent() == self._layout:
self._layout.remove(g._drawing_area)
self.create_window(g.handle)
else:
if g._window is not None:
g._layout.remove(g._drawing_area)
g._window.destroy()
# this is ugly, but I'm too lazy to refactor nvim_resize
# to fit the flow of information
if g._drawing_area.get_parent() != self._layout:
self._layout.add(g._drawing_area)
g._drawing_area.show()
if g._screen is not None:
x = g.options.x*self._cell_pixel_width
y = g.options.y*self._cell_pixel_height
w,h = g.pixel_size
if len(g.options.anchor) >= 2:
if g.options.anchor[0] == 'S':
y -= h
if g.options.anchor[1] == 'E':
x -= w
self._layout.move(g._drawing_area,x,y)

def _nvim_grid_cursor_goto(self, handle, row, col):
print("I",handle,file=sys.stderr)
self._curgrid = handle
if handle not in self.grids:
self.create_drawing_area(handle)
self.g = self.grids[handle]
self.g = self.get_grid(handle)
self._screen = self.g._screen
if self._screen is not None:
# TODO: this should really be asserted on the nvim side
row, col = min(row, self._screen.rows), min(col, self._screen.columns)
self._screen.cursor_goto(row,col)
self._drawing_area = self.g._drawing_area
self._window= self.g._window



def _nvim_resize(self, columns, rows):
Expand Down Expand Up @@ -207,7 +260,13 @@ def _nvim_resize(self, columns, rows):
self._cell_pixel_height = cell_pixel_height
self.g._screen = Screen(columns, rows)
self._screen = self.g._screen
self.g._window.resize(pixel_width, pixel_height)
self.g._drawing_area.set_size_request(pixel_width, pixel_height)
self.g.pixel_size = pixel_width, pixel_height
if self.g.options is not None:
self.configure_float(self.g)

if self.g._window is not None:
self.g._window.resize(pixel_width, pixel_height)

def _nvim_clear(self):
self._clear_region(self._screen.top, self._screen.bot + 1,
Expand Down Expand Up @@ -498,6 +557,9 @@ def _get_coords(self, row, col):
def _flush(self,g=None):
gs = [g] if g is not None else self.grids.values()
for g in gs:
if g._screen is None:
continue

row, startcol, endcol = g._pending
g._pending[0] = g._screen.row
g._pending[1] = g._screen.col
Expand Down

0 comments on commit 6b54183

Please sign in to comment.