Gregory F
Gregory F

Reputation: 23

Is there a way to deactivate mouse cursor in Gtk window/widget?

first my question: is there a way to simply deactivate the mouse cursor in a widget or in the all window? now the background for the question:

I am writing an app in which i want to display videos. When the video is playing i use keyboard shortcut to display and hide the progress bare and also to pause. So far every thing works fine except when my mouse cursor is in the window, than none of the key press event are working anymore. The only way to make them work again is to manually move the cursor out of the window. I rather not have to move manually the cursor and also an arrow in your video is rather annoying. That is why i am asking the question.

Here is a code sample:

import pafy, gi
gi.require_versions({'Gtk':'3.0', 'GdkX11':'3.0', 'Gst':'1.0', 'GstVideo':'1.0'})
from gi.repository import Gst, Gtk, GLib, GdkX11, GstVideo, GObject

vertical  = Gtk.Orientation.VERTICAL
horizontal = Gtk.Orientation.HORIZONTAL

link = #PLZ insrte here any youtube video link
vid = pafy.new(link)
best = vid.getbest()
uri = best.url

class GstWidget(Gtk.DrawingArea):

    def __init__(self):

        super().__init__()

        self.connect('draw', self.on_draw)
        self.connect('realize', self.on_realize)
        self.connect('unrealize', self.on_unrealize)

        # Create GStreamer pipeline
        self.pipeline = Gst.Pipeline()

        # Create bus to get events from GStreamer pipeline
        self.bus = self.pipeline.get_bus()
        self.bus.add_signal_watch()
        self.bus.connect('message::eos', self.on_eos)
        self.bus.connect('message::error', self.on_error)

        # This is needed to make the video output in our DrawingArea:
        self.bus.enable_sync_message_emission()
        self.bus.connect('sync-message::element', self.on_sync_message)

        # Create GStreamer elements
        self.playbin = Gst.ElementFactory.make('playbin', None)

        # Add playbin to the pipeline
        self.pipeline.add(self.playbin)

        # Set properties
        self.playbin.set_property('uri', uri)

    def on_realize(self, widget, data=None):
        print("on_relalize")

        window = widget.get_window()
        self.xid = window.get_xid()


    def on_draw(self, widget, cr):
        if self.playbin.get_state(0).state < Gst.State.PAUSED:
            allocation = widget.get_allocation()

            cr.set_source_rgb(0, 0, 0)
            cr.rectangle(0, 0, allocation.width, allocation.height)
            cr.fill()

        # self.on_realize(widget)

    def on_unrealize(self, widget, data=None):
        # to prevent racing conditions when closing the window while playing
        self.playbin.set_state(Gst.State.NULL)
        self.pipeline.set_state(Gst.State.NULL)

    def on_sync_message(self, bus, msg):
        if msg.get_structure().get_name() == 'prepare-window-handle':
            print('prepare-window-handle')

            print('on_sync', self.xid)
            self.playbin.set_window_handle(self.xid)

            print(msg)
            print(msg.src)


    def on_eos(self, bus, msg):
        self.pipeline.seek_simple(
            Gst.Format.TIME,
            Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
            0
        )

    def on_error(self, bus, msg):
        err, debug = message.parse_error()
        print(f"Error: {err}", debug)



class Master(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="Gst_test")

        button = Gtk.Button(label="Play")
        button.connect("clicked", self.on_button_clicked)

        self.add(button)

    def on_button_clicked(self, widget):

        for child in self.get_children():
            child.destroy()

        self.video_player = GstWidget()

        #main container
        self.main_box = Gtk.Box(orientation=vertical)

        #for the progress bar
        self.hbox = Gtk.Box(orientation=horizontal)

        #here we gona make our progressbar.
        self.slider = Gtk.Scale.new_with_range(horizontal, 0, 100, 0.5)
        # self.slider_handler_id = self.slider.connect("value-changed", self.on_slider_seek)
        self.hbox.pack_start(self.slider, True, True, 2)

        self.main_box.pack_start(self.video_player, True, True, 0)
        self.add(self.main_box)

        # set focus on the main_box and connect it to the key_pressed method
        self.main_box.set_can_focus(True)
        self.main_box.grab_focus()
        self.main_box.connect("key-press-event", self.key_pressed)

        self.show_all()

        #adding the progress bare after the show_all so we don't have it by default
        self.main_box.pack_start(self.hbox, False, False, 0)

        if self.video_player.playbin.get_state(0).state != Gst.State.PAUSED:
            self.video_player.pipeline.set_state(Gst.State.PLAYING)
        else:
            self.video_player.pipeline.set_state(Gst.State.PAUSED)

    def key_pressed(self, widget, event):
        #is the pressed key the up-arrow?
        if event.get_keyval()[1] == 65362:
            self.show_all()
        #is the pressed key the down-arrow?
        elif event.get_keyval()[1] == 65364:
            self.hbox.hide()
        #is key F11?
        elif event.get_keyval()[1] == 65480:
            print(f"{self.is_fullscreen=}")
        #is the pressed key the space-bar?
        elif event.get_keyval()[1] == 32:
            if self.video_player.playbin.get_state(0).state == Gst.State.PLAYING:
                self.video_player.pipeline.set_state(Gst.State.PAUSED)
                self.show_all()
            else:
                if self.video_player.playbin.get_state(0).state == Gst.State.PAUSED:
                    self.video_player.pipeline.set_state(Gst.State.PLAYING)
                    self.hbox.hide()
        #if it is any of the previous, just tell me which is.
        else:
            print(f"{__name__=} @ line 160, {event.get_keyval()}")



if __name__ == "__main__":
    Gst.init(None)
    root = Master()
    root.connect("delete-event", Gtk.main_quit)
    root.show_all()
    Gtk.main()

What i tried slash where i looked for answers: I searched in the documentations,and i haven't found how to do that, not in Gtk, not in Gdk, not in Gst. I found on line some article talking about Gst Navigate, but it was writen in C and i never learned it so it was not helpful to me. And the "navigate" it is not in the documentation i just linked.

I also found the some question in stackoverflow here but is is 5 years old and it seems to not be working nowadays. the Gtk.Gdk.Pixmap seems to not be usable anymore. Or maybe with an other name?

Thank you for your time

Upvotes: 2

Views: 967

Answers (1)

stovfl
stovfl

Reputation: 15523

Question: deactivate mouse cursor in Gtk window/widget?

It's the same as setting a new/different Cursor to a widget.
You have to wait for the realize signal.
If the widget's Gdk.Window hasn't been created yet, you can't change the cursor.

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GLib


class ApplicationWindow(Gtk.ApplicationWindow):
    def __init__(self):
        super().__init__()
        self.connect("destroy", Gtk.main_quit)
        self.set_size_request(100, 70)

        self.connect("realize", self.on_realize)
        GLib.timeout_add(interval=5000, function=self.reset_cursor)

    def on_realize(self, widget):
        # Step 1: Get the Gdk.Display for the toplevel for this widget.
        display = widget.get_display()

        # Step 2: Create a new Cursor of type BLANK_CURSOR
        cursor = Gdk.Cursor.new_for_display(display, Gdk.CursorType.BLANK_CURSOR)

        # Step 3: Get the widget’s Gdk.Window and set the new Cursor
        widget.get_window().set_cursor(cursor)

    def reset_cursor(self):
        cursor = Gdk.Cursor.new_from_name(self.get_display(), 'default')
        self.get_window().set_cursor(cursor)

if __name__ == "__main__":
    ApplicationWindow()
    Gtk.main()

Tested with Python: 3.5 - gi.__version__: 3.22.0

Upvotes: 2

Related Questions