Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ repos:
- "--markdown-linebreak-ext=md"
exclude: COPYING
- repo: https://github.com/PyCQA/flake8.git
rev: 3.9.2
rev: 7.3.0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't change our linter versions. Out of scope, do this in another PR.

hooks:
- id: flake8
- repo: https://github.com/PyCQA/pylint.git
rev: v2.13.6
rev: v3.3.9
hooks:
- id: pylint
- repo: https://github.com/psf/black.git
rev: 22.10.0
rev: 24.10.0
hooks:
- id: black
- repo: https://github.com/hackedd/fiximports.git
Expand Down
48 changes: 24 additions & 24 deletions guake/data/guake.glade
Original file line number Diff line number Diff line change
@@ -1,70 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!-- Generated with glade 3.40.0 -->
<interface domain="guake">
<requires lib="gtk+" version="3.10"/>
<object class="GtkMenu" id="tray-menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a convention change to go with the glade version bump I presume?

<child>
<object class="GtkImageMenuItem" id="prefs-menuitem">
<property name="label">gtk-preferences</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
<signal name="activate" handler="show_prefs" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="about-menuitem">
<property name="label">gtk-about</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
<signal name="activate" handler="show_about" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separador-mmenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="quit-menuitem">
<property name="label" translatable="yes">Quit</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_stock">False</property>
<property name="can-focus">False</property>
<property name="use-stock">False</property>
<signal name="activate" handler="accel_quit" swapped="no"/>
</object>
</child>
</object>
<object class="GtkWindow" id="window-root">
<property name="can_focus">False</property>
<property name="has_focus">True</property>
<property name="can-focus">False</property>
<property name="has-focus">True</property>
<property name="title" translatable="yes">Guake!</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="urgency_hint">True</property>
<property name="skip-taskbar-hint">True</property>
<property name="skip-pager-hint">True</property>
<property name="urgency-hint">True</property>
<property name="decorated">False</property>
<child>
<object class="GtkBox" id="mainframe">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkNotebook" id="notebook-teminals">
<property name="name">notebook-teminals</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="is_focus">True</property>
<property name="tab_pos">bottom</property>
<property name="show_tabs">False</property>
<property name="show_border">False</property>
<property name="enable_popup">True</property>
<property name="can-focus">True</property>
<property name="has-focus">True</property>
<property name="is-focus">True</property>
<property name="tab-pos">bottom</property>
<property name="show-tabs">False</property>
<property name="show-border">False</property>
<property name="enable-popup">True</property>
</object>
<packing>
<property name="expand">True</property>
Expand Down
14 changes: 12 additions & 2 deletions guake/gsettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,12 @@ def alignment_changed(self, settings, key, user_data):
"""If the gconf var window_halignment be changed, this method will
be called and will call the move function in guake.
"""
RectCalculator.set_final_window_rect(self.settings, self.guake.window)
# A persisted setting change should take priority over any in-memory
# size the user picked by dragging, so drop the stale override.
self.guake.settings_override = {}
RectCalculator.set_final_window_rect(
self.settings, self.guake.window, self.guake.settings_override
)
self.guake.set_tab_position()
self.guake.force_move_if_shown()

Expand All @@ -155,7 +160,12 @@ def size_changed(self, settings, key, user_data):
this method will be called and will call the resize function
in guake.
"""
RectCalculator.set_final_window_rect(self.settings, self.guake.window)
# A persisted setting change should take priority over any in-memory
# size the user picked by dragging, so drop the stale override.
self.guake.settings_override = {}
RectCalculator.set_final_window_rect(
self.settings, self.guake.window, self.guake.settings_override
)

def cursor_blink_mode_changed(self, settings, key, user_data):
"""Called when cursor blink mode settings has been changed"""
Expand Down
70 changes: 68 additions & 2 deletions guake/guake_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
from guake.utils import FullscreenManager
from guake.utils import HidePrevention
from guake.utils import RectCalculator
from guake.utils import SettingsOverride
from guake.utils import TabNameUtils
from guake.utils import get_server_time
from guake.utils import save_tabs_when_changed
Expand Down Expand Up @@ -190,6 +191,21 @@ def load_schema():
self.mainframe = self.get_widget("mainframe")
self.mainframe.remove(self.get_widget("notebook-teminals"))

# Window is undecorated (no WM title bar/borders), so provide a thin
# drag handle at the bottom edge to let users resize it manually.
# This is for issue: https://github.com/Guake/guake/issues/2337

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't put issue numbers in comments, just describe what the code does.

self.resize_handle = Gtk.EventBox()
self.resize_handle.set_size_request(-1, 8)
self.resize_handle.connect(
"realize",
lambda widget: widget.get_window().set_cursor(
Gdk.Cursor.new_from_name(Gdk.Display.get_default(), "ns-resize")
),
)
self.resize_handle.connect("button-press-event", self.on_resize_handle_button_press)
self.mainframe.pack_end(self.resize_handle, False, False, 0)
self.resize_handle.show()

# Pending restore for terminal split after show-up
# [(RootTerminalBox, TerminaBox, panes), ...]
self.pending_restore_page_split = []
Expand Down Expand Up @@ -223,6 +239,11 @@ def load_schema():
# Debounce accel_search_terminal
self.prev_accel_search_terminal_time = 0.0

# holds the GLib source id for the pending resize-debounce timeout
# used to capture resizing activities for https://github.com/Guake/guake/issues/2337

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar deal

self.resize_debounce_source_id = None
self.settings_override: SettingsOverride = {}

# holds the timestamp of the losefocus event
self.losefocus_time = 0

Expand All @@ -237,6 +258,7 @@ def load_schema():

self.window.connect("focus-out-event", self.on_window_losefocus)
self.window.connect("focus-in-event", self.on_window_takefocus)
self.window.connect("configure-event", self.on_window_configure)

# Handling the delete-event of the main window to avoid
# problems when closing it.
Expand Down Expand Up @@ -544,6 +566,45 @@ def losefocus_callback(sleep_time):
def on_window_takefocus(self, window, event):
self.takefocus_time = get_server_time(self.window)

def on_resize_handle_button_press(self, widget, event):
if event.button == 1:
self.window.begin_resize_drag(
Gdk.WindowEdge.SOUTH, event.button, int(event.x_root), int(event.y_root), event.time
)
return True

def on_window_configure(self, window, event):
"""Captures resizing activity for https://github.com/Guake/guake/issues/2337.

Using Debounce strategy with GLib to capture event when user has completed
resizing their window.
"""
if self.resize_debounce_source_id is not None:
GLib.source_remove(self.resize_debounce_source_id)

self.resize_debounce_source_id = GLib.timeout_add(
300, self.on_resize_debounced, event.width, event.height
)
return False

def on_resize_debounced(self, width, height):
self.resize_debounce_source_id = None

workarea = RectCalculator.get_final_window_monitor(
self.settings, self.window
).get_workarea()
if workarea.height <= 0 or workarea.width <= 0:
log.warning("Skipping resize-override update: invalid workarea %r", workarea)
return GLib.SOURCE_REMOVE

self.settings_override = SettingsOverride(
height_percentage=min(round(height / workarea.height * 100), 100),
width_percentage=min(round(width / workarea.width * 100), 100),
)

log.debug("Resize settled at %sx%s -> %r", width, height, self.settings_override)
return GLib.SOURCE_REMOVE

def show_menu(self, status_icon, button, activate_time):
"""Show the tray icon menu."""
menu = self.get_widget("tray-menu")
Expand Down Expand Up @@ -696,7 +757,9 @@ def show(self):

# setting window in all desktops

window_rect = RectCalculator.set_final_window_rect(self.settings, self.window)
window_rect = RectCalculator.set_final_window_rect(
self.settings, self.window, self.settings_override
)
self.window.stick()

# add tab must be called before window.show to avoid a
Expand All @@ -714,8 +777,11 @@ def show(self):
GLib.idle_add(lambda: self.window.move(window_rect.x, window_rect.y) and False)

# this works around an issue in fluxbox
# Note: re-applies the rect directly (rather than going through
# triggerOnChangedValue) so this synthetic re-trigger doesn't clear
# settings_override the way a real "window-height" change should.
if not self.fullscreen_manager.is_fullscreen():
self.settings.general.triggerOnChangedValue(self.settings.general, "window-height")
RectCalculator.set_final_window_rect(self.settings, self.window, self.settings_override)

time = get_server_time(self.window)

Expand Down
54 changes: 48 additions & 6 deletions guake/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import time
import yaml

from typing import TypedDict

import cairo

import gi
Expand All @@ -50,6 +52,19 @@
log = logging.getLogger(__name__)


class SettingsOverride(TypedDict, total=False):
"""Shape used to remember a window size the user picked by resizing.

When the user drags the window to a new height/width, that choice is
stored in memory with this shape and takes priority over the persisted
"window-height"/"window-width" gsettings values for the rest of the
current session, without overwriting those settings.
"""

height_percentage: int
width_percentage: int


def gdk_is_x11_display(instance):
if GdkX11:
return isinstance(instance, GdkX11.X11Display)
Expand Down Expand Up @@ -225,7 +240,8 @@ def unfullscreen(self):

# FIX to unfullscreen after show, fullscreen, hide, unfullscreen
# (unfullscreen breaks/does not shrink window size)
RectCalculator.set_final_window_rect(self.settings, self.window)
settings_override = self.guake.settings_override if self.guake else {}
RectCalculator.set_final_window_rect(self.settings, self.window, settings_override)

def toggle(self):
if self.is_fullscreen():
Expand All @@ -249,14 +265,40 @@ def toggle_fullscreen_hide_tabbar(self):

class RectCalculator:
@classmethod
def set_final_window_rect(cls, settings, window):
"""Sets the final size and location of the main window of guake. The height
is the window_height property, width is window_width and the
# pylint: disable-next=dangerous-default-value
def set_final_window_rect(
cls,
settings,
window,
settings_override: SettingsOverride = {},
):
"""Sets the final size and location of the main window of guake.

The height is the window_height property, width is window_width and the
horizontal alignment is given by window_alignment.

Args:
settings: The Guake Settings object, used to read the
window-height, window-width, window-halignment,
window-valignment and displacement values from gsettings.
window: The Gtk.Window (main Guake window) to resize and move.
settings_override: Optional height/width percentages that take
precedence over the persisted "window-height"/"window-width"
gsettings values for this call only, without writing them
back to gsettings. Falls back entirely to the persisted
settings when empty.

Returns:
Gdk.Rectangle: the computed window rectangle (position and size,
in screen coordinates) that was applied to the window.
"""
# fetch settings
height_percents = settings.general.get_int("window-height")
width_percents = settings.general.get_int("window-width")
height_percents = settings_override.get("height_percentage") or settings.general.get_int(
"window-height"
)
width_percents = settings_override.get("width_percentage") or settings.general.get_int(
"window-width"
)
halignment = settings.general.get_int("window-halignment")
valignment = settings.general.get_int("window-valignment")
vdisplacement = settings.general.get_int("window-vertical-displacement")
Expand Down
24 changes: 24 additions & 0 deletions releasenotes/notes/drag_resize-86950fd8fe5422c3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
release_summary: >
You can now resize the drop-down terminal by dragging its bottom edge,
similar to Windows Terminal - handy for temporarily expanding the
terminal to read long command output without leaving the drop-down view.

features:
- |
- Allow resizing the drop-down terminal by dragging its bottom edge (#2337).

known_issues:

upgrade:

deprecations:

security:

fixes:

translations:

notes_for_package_maintainers:

other:
Loading