18

In GTK (or pygtk or gtkmm...)

How can I detect that an application window has been manually resized by the user, as is typically done by dragging the window's edge?

I need to find a way to differentiate manual resizes from resizes that originate from gtk, such as changes in window content.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180

5 Answers5

8

Have you tried connecting to the GDK_CONFIGURE event?

Check out this example under the "Moving window" section. The example shows a callback doing something when the window is moved, but the configure event is a catch-all for moving, resizing and stack order events.

WorkingRobot
  • 423
  • 8
  • 19
luke
  • 36,103
  • 8
  • 58
  • 81
  • 2
    The following code works for this: g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(callback_func), NULL); – Sean Aug 31 '12 at 21:01
  • 1
    I think you can use "check-resize" instead "configure-event" – boldnik Jun 25 '13 at 14:43
  • But this doesn't provide a way to check what type of event occurred: resize or move. So surely if the user does not somehow find a way to determine that, this will produce spurious results. @boldnik: According to this, that will not work, as it fires for all kinds of other reasons: https://ubuntuforums.org/showthread.php?t=1100803&p=6927690#post6927690 – underscore_d May 26 '17 at 14:08
  • The given link is dead and the edit queue is full. Here's the current link to the example given: http://zetcode.com/gui/gtk2/ – Romário Nov 25 '20 at 20:30
  • @boldnik check_resize is triggered constantly at my side. I think configure-event is most likely the right direction. – Melroy van den Berg Feb 27 '22 at 23:49
7

I managed to pull this off by watching for size_allocate and size_request signals on the GtkWindow. If size_request ever got smaller, I called resize(1,1). If size_allocate was ever bigger than expected, I turned the system off.

One thing I made sure to handle was size_request returning big, then small, and having size_allocate be big and then small. I don't know if this is possible, but I fixed it by making sure to only decrease the expected values for size_allocate when I got a smaller size_allocate, not when I got a smaller size_request.

Make sure that your size_request handler comes after the base class' handler so that you get the right values. I did this by overriding the method and then calling the base class method first.

I've tried this in both 1 and 2 dimensions and it seems to work either way.

clahey
  • 4,795
  • 3
  • 27
  • 20
5

In my case I was trying to distinguish between a user resizing a Gtk.Paned from the user resizing the whole window. Both emitted the notify::position signal.

My solution was, since I can't know if the user is resizing the window from the widget, reverse what I wanted to know. Record if the user has re-positioned the widget and ignore updates if the user didn't initiate them on my widget.

That is to say, instead of testing "if window being resized" I recorded the button-press-event and button-release-event's locally so I could instead test "if widget being re-positioned"

from gi.repository import Gtk

class MyPaned(Gtk.Paned):
    _user_activated = False

    def on_position(self, _, gparamspec):
        if self._user_activated:
            # widget touched

        else:
            # window resized (probably)

    def on_button_press(self, *_):
        self._user_activated = True

    def on_button_release(self, *_):
        self._user_activated = False


    dev __init__(self, *args):
        super(MyPaned, self).__init__(*args)
        self.connect('notify::position', self.on_position)
        self.connect('button-press-event', self.on_button_press)
        self.connect('button-release-event', self.on_button_release)

Effectively by recorded when the user started and ended interacting with my widget directly, I could assume the rest of the time was due to the window being resized. (Until I find more cases)

ThorSummoner
  • 16,657
  • 15
  • 135
  • 147
  • Where in the API reference can I find the `notify::position`? – buhtz Apr 22 '18 at 22:10
  • 1
    @buhtz I think I stumbled into a "notify::" example in the wild, and I inferred the rest for Lazka's awesome PGI Docs: https://lazka.github.io/pgi-docs/#Gtk-3.0/classes/Paned.html – ThorSummoner Apr 22 '18 at 22:16
  • @ThorSummoner In the docs I nowhere can find a `notify::*` event. That is why I am wondering about. – buhtz Apr 23 '18 at 10:58
  • @ThorSummoner Yes, I wanted to add python3 syntax highlighting in your code snippet but SE tells me the *edit queue* of your answer is full. – Scrooge McDuck Dec 08 '20 at 02:15
  • @ScroogeMcDuck I've made the edited (great suggestion) maybe this clears the edit queue? I didn't see anything obvious about how to resolve that when I looked at the edit history of this answer – ThorSummoner Dec 08 '20 at 18:25
  • 1
    If there is a user that uses a tiling window manager, this code will not work as expected – Melroy van den Berg Feb 27 '22 at 23:49
4

In PyGTK, I've always watched for the expose_event for a window resize, then use the get_allocation method to get the new size.

eduffy
  • 39,140
  • 13
  • 95
  • 92
  • 1
    I'm looking at the GdkEventExpose structure...is it the send_event field that would tell me the user did it? – Drew Dormann Jun 29 '09 at 19:52
  • 2
    Actually, you probably want event_configure, not event_expose... my bad. I think that's called for both moves and resizes, so you'll have to remember the previous size if that's all you're interested in. – eduffy Jun 29 '09 at 20:27
1

You may be able to throw something together by using gdk_window_get_root_origin to get the top left corner of the window and gdk_window_get_geometry to get the width and height. Then you could hook a callback into the GDK_BUTTON_PRESS_MASK and check to see if the button press occurs near/on one of the edges of the window.

Of course, this seems quite hackish and it really bothers me that I couldn't find some simple way in the documentation for GdkWindow to do this. There is a gdk_window_begin_resize_drag function which really makes me think there's a cleaner way to do this, but I didn't see anything more obvious than my answer.

Eric
  • 268
  • 2
  • 9