Can anyone help on finding an tutorial or example code about gtk in-app notifications API reference
Asked Answered
D

2

8

I've recently studied the gtk design patterns, and found the in-app notifications. There is an description on when to use it, but no reference to the gtk api.

I have searched for it, but found just the GNotification and GApplication.send_notification, but this sends the notification to the desktop environment.

Can anyone help on finding an tutorial or example code for doing an in-app notification?

Dozer answered 1/8, 2017 at 7:28 Comment(4)
I would like to use this myself:) I therefore took the liberty to report no API reference to the link at the bottom of the page.Skater
I've send already an mail today, maybe it will not take too long :)Dozer
microo8 @Skater check the answer.Rasia
In case anyone is interested in doing this with GTK4, it is recommended to use AdwToast for the UI.Plantagenet
C
9

The app-notification "widget" is a mix of widgets, a css class and behaviors.

You should use a Gtk.Overlay in the window that you plan to use app-notifications then use a container (eg Gtk.Box) with the predefined app-notification style class. The notification container should be wrapped in a Gtk.Revealer to allow the reveal "slide" transition.

Here is a glade ui file (app-notification.ui) with an example:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <property name="default_width">640</property>
    <property name="default_height">480</property>
    <child>
      <placeholder/>
    </child>
    <child>
      <object class="GtkOverlay" id="overlay">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkBox" id="box1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="orientation">vertical</property>
            <child>
              <object class="GtkLabel" id="label1">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">APP-NOTIFICATION EXAMPLE</property>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="button1">
                <property name="label" translatable="yes">show app-notification</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="index">-1</property>
          </packing>
        </child>
        <child type="overlay">
          <object class="GtkRevealer" id="revealer2">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="halign">center</property>
            <property name="valign">start</property>
            <child>
              <object class="GtkBox" id="box2">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="valign">start</property>
                <property name="spacing">20</property>
                <child>
                  <object class="GtkLabel" id="label2">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="label" translatable="yes">This is an app-notification. Click the button to dismiss</property>
                  </object>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">True</property>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="button2">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="relief">none</property>
                    <child>
                      <object class="GtkImage" id="image2">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="icon_name">window-close-symbolic</property>
                      </object>
                    </child>
                    <style>
                      <class name="image-button"/>
                    </style>
                  </object>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">True</property>
                    <property name="position">1</property>
                  </packing>
                </child>
                <style>
                  <class name="app-notification"/>
                </style>
              </object>
            </child>
          </object>
        </child>
      </object>
    </child>
  </object>
</interface>

The result in Glade:

enter image description here

And here is some python code that uses the previous glade file and gives some dynamic behavior to the notification so that you can see it in action by clicking the buttons. The glade file should be named app-notification.ui, otherwise change the code to reflect the given name:

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

def onButtonShow(self):
    revealer.set_reveal_child(True)

def onButtonClose(self):
    revealer.set_reveal_child(False)

builder = Gtk.Builder()
builder.add_from_file("app-notification.ui")

window = builder.get_object("window1")

buttonShow = builder.get_object("button1")
buttonClose = builder.get_object ("button2")
revealer = builder.get_object("revealer2") 

buttonShow.connect ("clicked", onButtonShow)
buttonClose.connect ("clicked", onButtonClose)
window.connect ("destroy", Gtk.main_quit)
window.show_all()

Gtk.main()
Cynthiacynthie answered 1/8, 2017 at 12:1 Comment(3)
Out of curiosity, where did you find this info?Skater
@Skater to say the truth i don't really remember from where exactly but i did grasp css files to search for some classes names. Something like a cumulative search, Get A, with A got to B...then to C. A good approach is to remember some application that uses something that you want then go to the sources at github or gnome git and try to find how they have implemented it. Anyway you both were right. There's no documentation on how to achieve it. maybe we should add something like this to the Gnome/HowDoIRasia
@SamBull no, its redundant. I'll fix it.Rasia
D
2

If you prefer to create this without Glade, you can use something like this (based off the previous answer):

Assuming your current code has something like:

window = Gtk.ApplicationWindow(application=self)
window.add(main_widget)

Then you would change the code to something like this:

window = Gtk.ApplicationWindow(application=self)
overlay = Gtk.Overlay()
window.add(overlay)
overlay.add(main_widget)
self._notify_timeout = None

# Notification overlay widget
self._revealer = Gtk.Revealer(valign=Gtk.Align.START, halign=Gtk.Align.CENTER)
box = Gtk.Box(orientation="horizontal", spacing=18)
box.get_style_context().add_class("app-notification")
self._notify_label = Gtk.Label(wrap=True)
box.pack_start(self._notify_label, expand=False, fill=True, padding=18)
button = Gtk.Button.new_from_icon_name("window-close-symbolic", Gtk.IconSize.BUTTON)
button.set_relief(Gtk.ReliefStyle.NONE)
button.set_receives_default(True)
button.connect("clicked", functools.partial(self._revealer.set_reveal_child, False))
box.pack_start(button, expand=False, fill=True, padding=18)
self._revealer.add(box)
overlay.add_overlay(self._revealer)

Then to display a notification, you can add a method like:

def notify(self, message, timeout=5):
    if self._notify_timeout is not None:
        self._notify_timeout.cancel()

    self._notify_label.set_text(message)
    self._revealer.set_reveal_child(True)

    if timeout > 0:
        self._notify_timeout = asyncio.get_event_loop().call_later(
            timeout, functools.partial(self._revealer.set_reveal_child, False))

In addition to what the existing answer provides, this adds a timeout to automatically remove the notification after a few seconds. That code assumes you are using asyncio, if not then update the above method to use another timer method.

Disseminule answered 1/2, 2020 at 16:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.