Skip to content

Commit

Permalink
Logic for improved guake like terminal functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
maximstewart committed Feb 9, 2022
1 parent fc528b2 commit e1fe0a7
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 29 deletions.
12 changes: 12 additions & 0 deletions terminatorlib/optionparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ def parse_options():
parser.add_argument('--geometry', dest='geometry', type=str,
help=_('Set the preferred size and position of the window'
'(see X man page)'))
parser.add_argument('--guake-key', dest='guake_key', type=str,
help=_('If set, toggle window with given key'
'(see X man page)'))
parser.add_argument('--guake-side', dest='guake_side', default="top", type=str,
help=_('When using --guake-key, set argument to top, bottom, left, or right to bind to screen edge. Default: top'
'(see X man page)'))
parser.add_argument('--guake-width', dest='guake_width', default=800, type=int,
help=_('Set the preferred width when using Guake like mode. Default: 800'
'(see X man page)'))
parser.add_argument('--guake-height', dest='guake_height', default=600, type=int,
help=_('Set the preferred height when using Guake like mode. Default: 600'
'(see X man page)'))
if not is_x_terminal_emulator:
parser.add_argument('-e', '--command', dest='command',
help=_('Specify a command to execute inside the terminal'))
Expand Down
130 changes: 101 additions & 29 deletions terminatorlib/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,17 @@ def __init__(self):
# self.set_property('allow-shrink', True) # FIXME FOR GTK3, or do we need this actually?
icon_to_apply=''

self.register_callbacks()

self.apply_config()

self.title = WindowTitle(self)
self.title.update()

self.preventHide = False

self.preventHide = False

self.display = Gdk.Display().get_default()
self.mouse = self.display.get_default_seat().get_pointer()
self.guake_key = None

options = self.config.options_get()
if options:
Expand All @@ -92,15 +96,49 @@ def __init__(self):

if options.role:
self.set_role(options.role)

if options.forcedicon is not None:
icon_to_apply = options.forcedicon

if options.geometry:
if not self.parse_geometry(options.geometry):
err('Window::__init__: Unable to parse geometry: %s' %
err('Window::__init__: Unable to parse geometry: %s' %
options.geometry)

if options.guake_key:
self.guake_key = options.guake_key
if options.guake_side and options.guake_width and options.guake_height:
proceed_undecorated = True

if options.guake_side in ["top", "bottom", "left", "right"]:
self.guake_side = options.guake_side
else:
proceed_undecorated = False
err('Window::__init__: Unable to parse guake_side: %s' %
options.guake_side)

if type(options.guake_width) == int:
self.guake_width = options.guake_width
else:
proceed_undecorated = False
err('Window::__init__: Unable to parse guake_width: %s' %
options.guake_width)

if type(options.guake_height) == int:
self.guake_height = options.guake_height
else:
proceed_undecorated = False
err('Window::__init__: Unable to parse guake_height: %s' %
options.guake_height)

if proceed_undecorated:
self.set_decorated(False)
self.set_default_size(self.guake_width, self.guake_height)
else:
self.guake_key = None

self.register_callbacks()

self.apply_icon(icon_to_apply)
self.pending_set_rough_geometry_hint = False

Expand All @@ -118,6 +156,31 @@ def do_set_property(self, prop, value):
else:
raise AttributeError('unknown property %s' % prop.name)

# NOTE: Gdk.VisibilityState.UNOBSCURED presumably isn't reliable due to transparency in moddern wms.
# Seems to work okay for our needs but should be kept in mind for future changes....
def _bind_window_to_position(self, widget, eve):
if eve.state == Gdk.VisibilityState.UNOBSCURED:
screen, mouse_x, mouse_y = self.mouse.get_position()
monitor = self.display.get_monitor_at_point(mouse_x, mouse_y)
window_w, window_h = self.guake_width, self.guake_height
geom_rect = monitor.get_geometry()
x, y, w, h = geom_rect.x, geom_rect.y, geom_rect.width, geom_rect.height

if self.guake_side == "top":
new_x = (w - (window_w + ((w - window_w)/2) )) + x
new_y = y
if self.guake_side == "bottom":
new_x = (w - (window_w + ((w - window_w)/2) )) + x
new_y = (h - window_h) + y
if self.guake_side == "left":
new_x = x
new_y = (h - (window_h + ((h - window_h)/2) )) + y
if self.guake_side == "right":
new_x = (w - window_w) + x
new_y = (h - (window_h + ((h - window_h)/2) )) + y

self.move(new_x, new_y)

def register_callbacks(self):
"""Connect the GTK+ signals we care about"""
self.connect('key-press-event', self.on_key_press)
Expand All @@ -128,22 +191,29 @@ def register_callbacks(self):
self.connect('focus-out-event', self.on_focus_out)
self.connect('focus-in-event', self.on_focus_in)

if self.guake_key not in ('', None):
guake_unload_id = self.connect('visibility-notify-event', self._bind_window_to_position)

_hide_window = self.config['keybindings']['hide_window']
bind_key = self.guake_key if self.guake_key not in ('', None) else _hide_window if _hide_window not in ('', None) else None

# Attempt to grab a global hotkey for hiding the window.
# If we fail, we'll never hide the window, iconifying instead.
if self.config['keybindings']['hide_window'] not in ('', None):
if display_manager() == 'X11':
try:
self.hidebound = Keybinder.bind(
self.config['keybindings']['hide_window'],
self.on_hide_window)
except (KeyError, NameError):
pass

if not self.hidebound:
err('Unable to bind hide_window key, another instance/window has it.')
self.hidefunc = self.iconify
else:
self.hidefunc = self.hide
if bind_key and display_manager() == 'X11':
try:
self.hidebound = Keybinder.bind(bind_key, self.on_hide_window)
except (KeyError, NameError):
pass

if not self.hidebound:
err('Unable to bind hide_window key, another instance/window has it.')
self.hidefunc = self.iconify

if self.guake_key not in ('', None):
GObject.signal_handler_disconnect(self, guake_unload_id)
self.set_decorated(True)
else:
self.hidefunc = self.hide

def apply_config(self):
"""Apply various configuration options"""
Expand Down Expand Up @@ -293,7 +363,7 @@ def on_delete_event(self, window, event, data=None):
def confirm_close(self, window, type):
"""Display a confirmation dialog when the user is closing multiple
terminals in one window"""

return(not (self.construct_confirm_close(window, type) == Gtk.ResponseType.ACCEPT))

def on_destroy_event(self, widget, data=None):
Expand All @@ -317,8 +387,10 @@ def on_hide_window(self, data=None):
if (time.time() - self.losefocus_time < 0.1) and \
self.config['hide_on_lose_focus']:
return

if self.position:
self.move(self.position[0], self.position[1])

self.show()
self.grab_focus()
try:
Expand All @@ -333,7 +405,7 @@ def on_hide_window(self, data=None):
# pylint: disable-msg=W0613
def on_window_state_changed(self, window, event):
"""Handle the state of the window changing"""
self.isfullscreen = bool(event.new_window_state &
self.isfullscreen = bool(event.new_window_state &
Gdk.WindowState.FULLSCREEN)
self.ismaximised = bool(event.new_window_state &
Gdk.WindowState.MAXIMIZED)
Expand Down Expand Up @@ -392,7 +464,7 @@ def set_real_transparency(self, value=True):
visual = screen.get_rgba_visual()
if visual:
self.set_visual(visual)

def show(self, startup=False):
"""Undo the startup show request if started in hidden mode"""
#Present is necessary to grab focus when window is hidden from taskbar.
Expand Down Expand Up @@ -481,7 +553,7 @@ def split_axis(self, widget, vertical=True, cwd=None, sibling=None, widgetfirst=
container = maker.make('VPaned')
else:
container = maker.make('HPaned')

self.set_pos_by_ratio = True

if not sibling:
Expand All @@ -505,7 +577,7 @@ def split_axis(self, widget, vertical=True, cwd=None, sibling=None, widgetfirst=
for term in order:
container.add(term)
container.show_all()

while Gtk.events_pending():
Gtk.main_iteration_do(False)
sibling.grab_focus()
Expand Down Expand Up @@ -547,7 +619,7 @@ def zoom(self, widget, font_scale=True):
self.set_property('term_zoomed', True)

if font_scale:
widget.cnxids.new(widget, 'size-allocate',
widget.cnxids.new(widget, 'size-allocate',
widget.zoom_scale, self.zoom_data)

widget.grab_focus()
Expand Down Expand Up @@ -603,7 +675,7 @@ def rotate(self, widget, clockwise):

def get_terminals(self):
return(util.enumerate_descendants(self)[1])

def get_visible_terminals(self):
"""Walk down the widget tree to find all of the visible terminals.
Mostly using Container::get_visible_terminals()"""
Expand Down Expand Up @@ -693,7 +765,7 @@ def set_rough_geometry_hints(self):
extra_height = win_height - total_font_height

dbg('setting geometry hints: (ewidth:%s)(eheight:%s),\
(fwidth:%s)(fheight:%s)' % (extra_width, extra_height,
(fwidth:%s)(fheight:%s)' % (extra_width, extra_height,
font_width, font_height))
geometry = Gdk.Geometry()
geometry.base_width = extra_width
Expand Down Expand Up @@ -817,7 +889,7 @@ def ungroup_tab(self, widget):
if not maker.isinstance(notebook, 'Notebook'):
dbg('note in a notebook, refusing to ungroup tab')
return

self.set_groups(None, self.get_visible_terminals())

def move_tab(self, widget, direction):
Expand Down Expand Up @@ -850,7 +922,7 @@ def move_tab(self, widget, direction):
else:
err('unknown direction: %s' % direction)
return

notebook.reorder_child(child, page)

def navigate_terminal(self, terminal, direction):
Expand Down

0 comments on commit e1fe0a7

Please sign in to comment.