Use wx_is_at_least_gtk2(minor) instead of gtk_check_version(2, minor) because it is more clear and also works as expected (i.e. returns true) when using GTK+ 3 instead of creating difficult to notice bugs in the code by failing the version check in this case. See #18004.
346 lines
9.0 KiB
C++
346 lines
9.0 KiB
C++
/////////////////////////////////////////////////////////////////////////
|
|
// File: src/gtk/taskbar.cpp
|
|
// Purpose: wxTaskBarIcon
|
|
// Author: Vaclav Slavik
|
|
// Modified by: Paul Cornett
|
|
// Created: 2004/05/29
|
|
// Copyright: (c) Vaclav Slavik, 2004
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#if wxUSE_TASKBARICON
|
|
|
|
#include "wx/taskbar.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/toplevel.h"
|
|
#include "wx/menu.h"
|
|
#include "wx/icon.h"
|
|
#endif
|
|
|
|
#include <gtk/gtk.h>
|
|
#ifdef GDK_WINDOWING_X11
|
|
#include <gdk/gdkx.h>
|
|
#endif
|
|
#ifndef __WXGTK3__
|
|
#include "eggtrayicon.h"
|
|
#endif
|
|
#include "wx/gtk/private/gtk2-compat.h"
|
|
|
|
#if !GTK_CHECK_VERSION(2,10,0)
|
|
typedef struct _GtkStatusIcon GtkStatusIcon;
|
|
#endif
|
|
|
|
class wxTaskBarIcon::Private
|
|
{
|
|
public:
|
|
Private(wxTaskBarIcon* taskBarIcon);
|
|
~Private();
|
|
void SetIcon();
|
|
void size_allocate(int width, int height);
|
|
|
|
// owning wxTaskBarIcon
|
|
wxTaskBarIcon* m_taskBarIcon;
|
|
// used when GTK+ >= 2.10
|
|
GtkStatusIcon* m_statusIcon;
|
|
// for PopupMenu
|
|
wxWindow* m_win;
|
|
wxBitmap m_bitmap;
|
|
wxString m_tipText;
|
|
#ifndef __WXGTK3__
|
|
// used when GTK+ < 2.10
|
|
GtkWidget* m_eggTrayIcon;
|
|
// for tooltip when GTK+ < 2.10
|
|
GtkTooltips* m_tooltips;
|
|
// width and height of available space, only used when GTK+ < 2.10
|
|
int m_size;
|
|
#endif
|
|
};
|
|
//-----------------------------------------------------------------------------
|
|
|
|
extern "C" {
|
|
#ifndef __WXGTK3__
|
|
static void
|
|
icon_size_allocate(GtkWidget*, GtkAllocation* alloc, wxTaskBarIcon::Private* priv)
|
|
{
|
|
priv->size_allocate(alloc->width, alloc->height);
|
|
}
|
|
|
|
static void
|
|
icon_destroy(GtkWidget*, wxTaskBarIcon::Private* priv)
|
|
{
|
|
// Icon window destroyed, probably because tray program has died.
|
|
// Recreate icon so it will appear if tray program is restarted.
|
|
priv->m_eggTrayIcon = NULL;
|
|
priv->SetIcon();
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
icon_activate(void*, wxTaskBarIcon* taskBarIcon)
|
|
{
|
|
// activate occurs from single click with GTK+
|
|
wxTaskBarIconEvent event(wxEVT_TASKBAR_LEFT_DOWN, taskBarIcon);
|
|
if (!taskBarIcon->SafelyProcessEvent(event))
|
|
{
|
|
// if single click not handled, send double click for compatibility
|
|
event.SetEventType(wxEVT_TASKBAR_LEFT_DCLICK);
|
|
taskBarIcon->SafelyProcessEvent(event);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
icon_popup_menu(GtkWidget*, wxTaskBarIcon* taskBarIcon)
|
|
{
|
|
wxTaskBarIconEvent event(wxEVT_TASKBAR_CLICK, taskBarIcon);
|
|
taskBarIcon->SafelyProcessEvent(event);
|
|
return true;
|
|
}
|
|
|
|
#ifndef __WXGTK3__
|
|
static gboolean
|
|
icon_button_press_event(GtkWidget*, GdkEventButton* event, wxTaskBarIcon* taskBarIcon)
|
|
{
|
|
if (event->type == GDK_BUTTON_PRESS)
|
|
{
|
|
if (event->button == 1)
|
|
icon_activate(NULL, taskBarIcon);
|
|
else if (event->button == 3)
|
|
icon_popup_menu(NULL, taskBarIcon);
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
#if GTK_CHECK_VERSION(2,10,0)
|
|
static void
|
|
status_icon_popup_menu(GtkStatusIcon*, guint, guint, wxTaskBarIcon* taskBarIcon)
|
|
{
|
|
icon_popup_menu(NULL, taskBarIcon);
|
|
}
|
|
#endif
|
|
} // extern "C"
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool wxTaskBarIconBase::IsAvailable()
|
|
{
|
|
#ifdef GDK_WINDOWING_X11
|
|
if (!GDK_IS_X11_DISPLAY(gdk_display_get_default()))
|
|
return false;
|
|
|
|
char name[32];
|
|
g_snprintf(name, sizeof(name), "_NET_SYSTEM_TRAY_S%d",
|
|
gdk_x11_get_default_screen());
|
|
Atom atom = gdk_x11_get_xatom_by_name(name);
|
|
|
|
Window manager = XGetSelectionOwner(gdk_x11_get_default_xdisplay(), atom);
|
|
|
|
return manager != None;
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
wxTaskBarIcon::Private::Private(wxTaskBarIcon* taskBarIcon)
|
|
{
|
|
m_taskBarIcon = taskBarIcon;
|
|
m_statusIcon = NULL;
|
|
m_win = NULL;
|
|
#ifndef __WXGTK3__
|
|
m_eggTrayIcon = NULL;
|
|
m_tooltips = NULL;
|
|
m_size = 0;
|
|
#endif
|
|
}
|
|
|
|
wxTaskBarIcon::Private::~Private()
|
|
{
|
|
if (m_statusIcon)
|
|
g_object_unref(m_statusIcon);
|
|
#ifndef __WXGTK3__
|
|
else if (m_eggTrayIcon)
|
|
{
|
|
g_signal_handlers_disconnect_by_func(m_eggTrayIcon, (void*)icon_destroy, this);
|
|
gtk_widget_destroy(m_eggTrayIcon);
|
|
}
|
|
#endif
|
|
if (m_win)
|
|
{
|
|
m_win->PopEventHandler();
|
|
m_win->Destroy();
|
|
}
|
|
#ifndef __WXGTK3__
|
|
if (m_tooltips)
|
|
{
|
|
gtk_object_destroy(GTK_OBJECT(m_tooltips));
|
|
g_object_unref(m_tooltips);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void wxTaskBarIcon::Private::SetIcon()
|
|
{
|
|
#if GTK_CHECK_VERSION(2,10,0)
|
|
if (wx_is_at_least_gtk2(10))
|
|
{
|
|
if (m_statusIcon)
|
|
gtk_status_icon_set_from_pixbuf(m_statusIcon, m_bitmap.GetPixbuf());
|
|
else
|
|
{
|
|
m_statusIcon = gtk_status_icon_new_from_pixbuf(m_bitmap.GetPixbuf());
|
|
g_signal_connect(m_statusIcon, "activate",
|
|
G_CALLBACK(icon_activate), m_taskBarIcon);
|
|
g_signal_connect(m_statusIcon, "popup_menu",
|
|
G_CALLBACK(status_icon_popup_menu), m_taskBarIcon);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifndef __WXGTK3__
|
|
m_size = 0;
|
|
if (m_eggTrayIcon)
|
|
{
|
|
GtkWidget* image = gtk_bin_get_child(GTK_BIN(m_eggTrayIcon));
|
|
gtk_image_set_from_pixbuf(GTK_IMAGE(image), m_bitmap.GetPixbuf());
|
|
}
|
|
else
|
|
{
|
|
m_eggTrayIcon = GTK_WIDGET(egg_tray_icon_new("wxTaskBarIcon"));
|
|
gtk_widget_add_events(m_eggTrayIcon, GDK_BUTTON_PRESS_MASK);
|
|
g_signal_connect(m_eggTrayIcon, "size_allocate",
|
|
G_CALLBACK(icon_size_allocate), this);
|
|
g_signal_connect(m_eggTrayIcon, "destroy",
|
|
G_CALLBACK(icon_destroy), this);
|
|
g_signal_connect(m_eggTrayIcon, "button_press_event",
|
|
G_CALLBACK(icon_button_press_event), m_taskBarIcon);
|
|
g_signal_connect(m_eggTrayIcon, "popup_menu",
|
|
G_CALLBACK(icon_popup_menu), m_taskBarIcon);
|
|
GtkWidget* image = gtk_image_new_from_pixbuf(m_bitmap.GetPixbuf());
|
|
gtk_container_add(GTK_CONTAINER(m_eggTrayIcon), image);
|
|
gtk_widget_show_all(m_eggTrayIcon);
|
|
}
|
|
#endif
|
|
}
|
|
#if wxUSE_TOOLTIPS
|
|
const char *tip_text = NULL;
|
|
if (!m_tipText.empty())
|
|
tip_text = m_tipText.utf8_str();
|
|
|
|
#if GTK_CHECK_VERSION(2,10,0)
|
|
if (m_statusIcon)
|
|
{
|
|
#if GTK_CHECK_VERSION(2,16,0)
|
|
if (wx_is_at_least_gtk2(16))
|
|
gtk_status_icon_set_tooltip_text(m_statusIcon, tip_text);
|
|
else
|
|
#endif
|
|
{
|
|
#ifndef __WXGTK3__
|
|
gtk_status_icon_set_tooltip(m_statusIcon, tip_text);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
#endif // GTK_CHECK_VERSION(2,10,0)
|
|
{
|
|
#ifndef __WXGTK3__
|
|
if (tip_text && m_tooltips == NULL)
|
|
{
|
|
m_tooltips = gtk_tooltips_new();
|
|
g_object_ref(m_tooltips);
|
|
gtk_object_sink(GTK_OBJECT(m_tooltips));
|
|
}
|
|
if (m_tooltips)
|
|
gtk_tooltips_set_tip(m_tooltips, m_eggTrayIcon, tip_text, "");
|
|
#endif
|
|
}
|
|
#endif // wxUSE_TOOLTIPS
|
|
}
|
|
|
|
#ifndef __WXGTK3__
|
|
void wxTaskBarIcon::Private::size_allocate(int width, int height)
|
|
{
|
|
int size = height;
|
|
EggTrayIcon* icon = EGG_TRAY_ICON(m_eggTrayIcon);
|
|
if (egg_tray_icon_get_orientation(icon) == GTK_ORIENTATION_VERTICAL)
|
|
size = width;
|
|
if (m_size == size)
|
|
return;
|
|
m_size = size;
|
|
int w = m_bitmap.GetWidth();
|
|
int h = m_bitmap.GetHeight();
|
|
if (w > size || h > size)
|
|
{
|
|
if (w > size) w = size;
|
|
if (h > size) h = size;
|
|
GdkPixbuf* pixbuf =
|
|
gdk_pixbuf_scale_simple(m_bitmap.GetPixbuf(), w, h, GDK_INTERP_BILINEAR);
|
|
GtkImage* image = GTK_IMAGE(gtk_bin_get_child(GTK_BIN(m_eggTrayIcon)));
|
|
gtk_image_set_from_pixbuf(image, pixbuf);
|
|
g_object_unref(pixbuf);
|
|
}
|
|
}
|
|
#endif
|
|
//-----------------------------------------------------------------------------
|
|
|
|
wxIMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler);
|
|
|
|
wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType WXUNUSED(iconType))
|
|
{
|
|
m_priv = new Private(this);
|
|
}
|
|
|
|
wxTaskBarIcon::~wxTaskBarIcon()
|
|
{
|
|
delete m_priv;
|
|
}
|
|
|
|
bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
|
|
{
|
|
m_priv->m_bitmap = icon;
|
|
m_priv->m_tipText = tooltip;
|
|
m_priv->SetIcon();
|
|
return true;
|
|
}
|
|
|
|
bool wxTaskBarIcon::RemoveIcon()
|
|
{
|
|
delete m_priv;
|
|
m_priv = new Private(this);
|
|
return true;
|
|
}
|
|
|
|
bool wxTaskBarIcon::IsIconInstalled() const
|
|
{
|
|
#ifdef __WXGTK3__
|
|
return m_priv->m_statusIcon != NULL;
|
|
#else
|
|
return m_priv->m_statusIcon || m_priv->m_eggTrayIcon;
|
|
#endif
|
|
}
|
|
|
|
bool wxTaskBarIcon::PopupMenu(wxMenu* menu)
|
|
{
|
|
#if wxUSE_MENUS
|
|
if (m_priv->m_win == NULL)
|
|
{
|
|
m_priv->m_win = new wxTopLevelWindow(
|
|
NULL, wxID_ANY, wxString(), wxDefaultPosition, wxDefaultSize, 0);
|
|
m_priv->m_win->PushEventHandler(this);
|
|
}
|
|
wxPoint point(-1, -1);
|
|
#ifdef __WXUNIVERSAL__
|
|
point = wxGetMousePosition();
|
|
#endif
|
|
m_priv->m_win->PopupMenu(menu, point);
|
|
#endif // wxUSE_MENUS
|
|
return true;
|
|
}
|
|
|
|
#endif // wxUSE_TASKBARICON
|