Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. How to properly show a window after clicking on a notification?
Forum Updated to NodeBB v4.3 + New Features

How to properly show a window after clicking on a notification?

Scheduled Pinned Locked Moved Unsolved Qt for Python
qt for python
4 Posts 2 Posters 415 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    RoinujNosde
    wrote on last edited by
    #1

    Hello,
    I'm wondering what's the proper way to show my window after clicking on a notification?

    This is what I've tried:

    def callback(*_):
        mainWindow.show()
        mainWindow.raise_()
        mainWindow.activateWindow()
    
    notification.addAction('default', '', callback) #notification sent using dbus
    notification.show()
    

    But it has a undesired behaviour:
    when clicking on the notification, the notification center (I'm on Gnome) stays open on top of my window.

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      What is your notification object ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      R 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi and welcome to devnet,

        What is your notification object ?

        R Offline
        R Offline
        RoinujNosde
        wrote on last edited by
        #3

        @SGaist
        Here's a reproducible example:

        import sys
        from PyQt6.QtWidgets import QApplication, QWidget, QPushButton
        from PyQt6.QtGui import QIcon
        from PyQt6.QtCore import pyqtSlot
        import dbus
        from collections import OrderedDict
        
        
        #   Copyright (c) 2018 Kurt Jacobson
        #      <kurtcjacobson@gmail.com>
        #
        # This program is free software: you can redistribute it and/or modify
        # it under the terms of the GNU General Public License as published by
        # the Free Software Foundation, either version 2 of the License, or
        # (at your option) any later version.
        #
        # This program is distributed in the hope that it will be useful,
        # but WITHOUT ANY WARRANTY; without even the implied warranty of
        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        # GNU General Public License for more details.
        DBusGMainLoop = None
        try:
            from dbus.mainloop.glib import DBusGMainLoop
        except:
            print ("Could not import DBusGMainLoop, is package 'python-dbus.mainloop.glib' installed?")
        
        APP_NAME = 'test'
        DBUS_IFACE = None
        NOTIFICATIONS = {}
        
        class Urgency:
            """freedesktop.org notification urgency levels"""
            LOW, NORMAL, CRITICAL = range(3)
        
        class UninitializedError(RuntimeError):
            """Error raised if you try to show an error before initializing"""
            pass
        
        def init():
            """Initializes the DBus connection"""
            global DBUS_IFACE
        
            name = "org.freedesktop.Notifications"
            path = "/org/freedesktop/Notifications"
            interface = "org.freedesktop.Notifications"
        
            mainloop = None
            if DBusGMainLoop is not None:
                mainloop = DBusGMainLoop(set_as_default=True)
        
            bus = dbus.SessionBus(mainloop)
            proxy = bus.get_object(name, path)
            DBUS_IFACE = dbus.Interface(proxy, interface)
        
            if mainloop is not None:
                # We have a mainloop, so connect callbacks
                DBUS_IFACE.connect_to_signal('ActionInvoked', _onActionInvoked)
                DBUS_IFACE.connect_to_signal('NotificationClosed', _onNotificationClosed)
        
        def _onActionInvoked(nid, action):
            """Called when a notification action is clicked"""
            nid, action = int(nid), str(action)
            try:
                notification = NOTIFICATIONS[nid]
            except KeyError:
                # must have been created by some other program
                return
            notification._onActionInvoked(action)
        
        def _onNotificationClosed(nid, reason):
            """Called when the notification is closed"""
            nid, reason = int(nid), int(reason)
            try:
                notification = NOTIFICATIONS[nid]
            except KeyError:
                # must have been created by some other program
                return
            notification._onNotificationClosed(notification)
            del NOTIFICATIONS[nid]
        
        class Notification(object):
            """Notification object"""
        
            id = 0
            timeout = -1
            _onNotificationClosed = lambda *args: None
        
            def __init__(self, title, body='', icon='', timeout=-1):
                """Initializes a new notification object.
        
                Args:
                    title (str):              The title of the notification
                    body (str, optional):     The body text of the notification
                    icon (str, optional):     The icon to display with the notification
                    timeout (TYPE, optional): The time in ms before the notification hides, -1 for default, 0 for never
                """
        
                self.title = title              # title of the notification
                self.body = body                # the body text of the notification
                self.icon = icon                # the path to the icon to use
                self.timeout = timeout          # time in ms before the notification disappears
                self.hints = {}                 # dict of various display hints
                self.actions = OrderedDict()    # actions names and their callbacks
                self.data = {}                  # arbitrary user data
        
            def show(self):
                if DBUS_IFACE is None:
                    raise UninitializedError("You must call 'notify.init()' before 'notify.show()'")
        
                """Asks the notification server to show the notification"""
                nid = DBUS_IFACE.Notify(APP_NAME,
                                   self.id,
                                   self.icon,
                                   self.title,
                                   self.body,
                                   self._makeActionsList(),
                                   self.hints,
                                   self.timeout,
                                )
        
                self.id = int(nid)
        
                NOTIFICATIONS[self.id] = self
                return True
        
            def close(self):
                """Ask the notification server to close the notification"""
                if self.id != 0:
                    DBUS_IFACE.CloseNotification(self.id)
        
            def onClosed(self, callback):
                """Set the callback called when the notification is closed"""
                self._onNotificationClosed = callback
        
            def addAction(self, action, label, callback, user_data=None):
                """Add an action to the notification.
        
                Args:
                    action (str):               A sort key identifying the action
                    label (str):                The text to display on the action button
                    callback (bound method):    The method to call when the action is activated
                    user_data (any, optional):  Any user data to be passed to the action callback
                """
                self.actions[action] = (label, callback, user_data)
        
            def _makeActionsList(self):
                """Make the actions array to send over DBus"""
                arr = []
                for action, (label, callback, user_data) in self.actions.items():
                    arr.append(action)
                    arr.append(label)
                return arr
        
            def _onActionInvoked(self, action):
                """Called when the user activates a notification action"""
                try:
                    label, callback, user_data = self.actions[action]
                except KeyError:
                    return
        
                if user_data is None:
                    callback(self, action)
                else:
                    callback(self, action, user_data)
                    
        def window():
           app = QApplication(sys.argv)
           widget = QWidget()
        
           button = QPushButton("Notify", widget)
           button.move(110,85)
           def button_callback():
           	notification = Notification("Test")
           	def notification_callback(*_):
        	    widget.show()
        	    widget.raise_() 
        	    widget.activateWindow()
        	    notification.close()
           	notification.addAction("default", "", notification_callback)
           	notification.show()
           button.clicked.connect(button_callback)
        
           widget.setGeometry(50,50,320,200)
           widget.setWindowTitle("My Window")
           widget.show()
           init()
           sys.exit(app.exec())
        
        if __name__ == '__main__':
           window()
        
        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          I wonder if the two event loops are not walking on each other's foot.

          That said, since you want to use DBus, why not use Qt's QtDBus module to ensure proper integration in your application ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          1

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved