如何将kylix加入到系统托盘(gtkplug)

/*systray.h*/
/* most of this ripped from gaim */

#include <gtk/gtkplug.h>
#include <gdk/gdkx.h>

G_BEGIN_DECLS

#define TYPE_TRAY_ICON (tray_icon_get_type ())
#define TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TRAY_ICON, TrayIcon))
#define TRAY_ICON_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), TYPE_TRAY_ICON, TrayIconClass))
#define IS_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TRAY_ICON))
#define TRAY_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_TRAY_ICON, TrayIconClass))

typedef struct {
  GtkPlug parent_instance;
  guint stamp;
  Atom selection_atom;
  Atom manager_atom;
  Atom system_tray_opcode_atom;
  Window manager_window;
} TrayIcon;

typedef struct {
  GtkPlugClass parent_class;
} TrayIconClass;

GType tray_icon_get_type (void);

TrayIcon *tray_icon_new (const gchar *name);
guint tray_icon_send_message (TrayIcon *icon, gint timeout, const gchar *msg, gint len);
void tray_icon_cancel_messsage (TrayIcon *icon, guint id);
gboolean docklet_create (void);

G_END_DECLS

 

 

 

#######################################

/*systray.c*/
/* most of this ripped from gaim */

#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include "systray.h"

#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2

static GtkPlugClass *parent_class = NULL;
static void tray_icon_init (TrayIcon *icon);
static void tray_icon_class_init (TrayIconClass *class);
static void tray_icon_unrealize (GtkWidget *widget);
static void tray_icon_update_manager_window (TrayIcon *icon);

enum systray_status {
  offline,
  online
};

gboolean systray_create ();
static gboolean systray_update_status ();
static TrayIcon *systray = NULL;
static GtkWidget *image = NULL;
static enum systray_status status;
static enum systray_status icon, is_online=online, is_offline=0;

GType tray_icon_get_type (void)
{
  static GType our_type = 0;

  our_type = g_type_from_name ("TrayIcon");

  if (our_type == 0) {
    static const GTypeInfo our_info = {
      sizeof (TrayIconClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL,
      (GClassInitFunc) tray_icon_class_init, NULL, NULL, sizeof (TrayIcon), 0,
      (GInstanceInitFunc) tray_icon_init};

    our_type = g_type_register_static (GTK_TYPE_PLUG, "TrayIcon", &our_info, 0);
  } else if (parent_class == NULL) {
    tray_icon_class_init ((TrayIconClass *)g_type_class_peek (our_type));
  }

  return our_type;
}

static void tray_icon_init (TrayIcon *icon)
{
  icon->stamp = 1;

  gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
}

static void tray_icon_class_init (TrayIconClass *class)
{
  GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
  parent_class = g_type_class_peek_parent (class);
  widget_class->unrealize = tray_icon_unrealize;
}

static GdkFilterReturn tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
{
  TrayIcon *icon = data;
  XEvent *xev = (XEvent *)xevent;

  if (xev->xany.type == ClientMessage && xev->xclient.message_type == icon->manager_atom &&
      xev->xclient.data.l[1] == icon->selection_atom) {
    tray_icon_update_manager_window (icon);
  } else if (xev->xany.window == icon->manager_window) {
    if (xev->xany.type == DestroyNotify) {
      tray_icon_update_manager_window (icon);
    }
  }

  return GDK_FILTER_CONTINUE;
}

static void tray_icon_unrealize (GtkWidget *widget)
{
  TrayIcon *icon = TRAY_ICON (widget);
  GdkWindow *root_window;

  if (icon->manager_window != None) {
    GdkWindow *gdkwin;

    gdkwin = gdk_window_lookup (icon->manager_window);

    gdk_window_remove_filter (gdkwin, tray_icon_manager_filter, icon);
  }

  root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ());
  
  gdk_window_remove_filter (root_window, tray_icon_manager_filter, icon);

  if (GTK_WIDGET_CLASS (parent_class)->unrealize) {
    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
  }
}

static void tray_icon_send_manager_message (TrayIcon *icon, long message, Window window,long data1, long data2, long data3)
{
  XClientMessageEvent ev;
  Display *display;

  ev.type = ClientMessage;
  ev.window = window;
  ev.message_type = icon->system_tray_opcode_atom;
  ev.format = 32;
  ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
  ev.data.l[1] = message;
  ev.data.l[2] = data1;
  ev.data.l[3] = data2;
  ev.data.l[4] = data3;

  display = gdk_display;

  gdk_error_trap_push ();
  XSendEvent (display, icon->manager_window, False, NoEventMask, (XEvent *)&ev);
  gdk_error_trap_pop ();
}

static void tray_icon_send_dock_request (TrayIcon *icon)
{
  tray_icon_send_manager_message (icon, SYSTEM_TRAY_REQUEST_DOCK,icon->manager_window, gtk_plug_get_id (GTK_PLUG (icon)), 0, 0);
}

static void tray_icon_update_manager_window (TrayIcon *icon)
{
  Display *xdisplay;

  xdisplay = gdk_display;

  if (icon->manager_window != None) {
    GdkWindow *gdkwin;

    gdkwin = gdk_window_lookup (icon->manager_window);
    gdk_window_remove_filter (gdkwin, tray_icon_manager_filter, icon);
  }

  XGrabServer (xdisplay);

  icon->manager_window = XGetSelectionOwner (xdisplay, icon->selection_atom);

  if (icon->manager_window != None) {
    XSelectInput (xdisplay, icon->manager_window, StructureNotifyMask);
  }

  XUngrabServer (xdisplay);
  XFlush (xdisplay);

  if (icon->manager_window != None) {
    GdkWindow *gdkwin;

    gdkwin = gdk_window_lookup (icon->manager_window);

    gdk_window_add_filter (gdkwin, tray_icon_manager_filter, icon);

    tray_icon_send_dock_request (icon);
  }
}

TrayIcon *tray_icon_new_for_xscreen (Screen *xscreen, const char *name)
{
  TrayIcon *icon;
  char buffer[256];
  GdkWindow *root_window;

  g_return_val_if_fail (xscreen != NULL, NULL);

  icon = g_object_new (TYPE_TRAY_ICON, NULL);
  gtk_window_set_title (GTK_WINDOW (icon), name);

  gtk_plug_construct (GTK_PLUG (icon), 0);

  gtk_widget_realize (GTK_WIDGET (icon));
  g_snprintf (buffer, sizeof (buffer), "_NET_SYSTEM_TRAY_S%d", XScreenNumberOfScreen (xscreen));
  icon->selection_atom = XInternAtom (DisplayOfScreen (xscreen), buffer, False);
  icon->system_tray_opcode_atom = XInternAtom (DisplayOfScreen (xscreen), "_NET_SYSTEM_TRAY_OPCODE", False);
  tray_icon_update_manager_window (icon);

  root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ());

  gdk_window_add_filter (root_window, tray_icon_manager_filter, icon);

  return icon;
}

TrayIcon *tray_icon_new (const gchar *name)
{
  TrayIcon *icon;
  icon = tray_icon_new_for_xscreen (DefaultScreenOfDisplay (gdk_display), name);
  //systray_create ();
  return icon;
}

guint tray_icon_send_message (TrayIcon *icon, gint timeout, const gchar *msg, gint len)
{
  guint stamp;

  g_return_val_if_fail (IS_TRAY_ICON (icon), 0);
  g_return_val_if_fail (timeout >= 0, 0);
  g_return_val_if_fail (msg != NULL, 0);

  if (icon->manager_window == None) {
    return 0;
  }

  if (len < 0) {
    len = strlen (msg);
  }

  stamp = icon->stamp++;

  tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE, (Window)gtk_plug_get_id (GTK_PLUG (icon)),timeout, len, stamp);

  gdk_error_trap_push ();
  while (len > 0) {
    XClientMessageEvent ev;
    Display *xdisplay;

    xdisplay = gdk_display;

    ev.type = ClientMessage;
    ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
    ev.format = 8;
    ev.message_type = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);

    if (len > 20) {
      memcpy (&ev.data, msg, 20);
      len -= 20;
      msg += 20;
    } else {
      memcpy (&ev.data, msg, len);
      len = 0;
    }

    XSendEvent (xdisplay, icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
    XSync (xdisplay, False);
  }
  gdk_error_trap_pop ();

  return stamp;
}

void tray_icon_cancel_message (TrayIcon *icon, guint id)
{
  g_return_if_fail (IS_TRAY_ICON (icon));
  g_return_if_fail (id > 0);

  tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE, (Window)gtk_plug_get_id (GTK_PLUG (icon)),id, 0, 0);
}

static void connect (GtkWidget *w, void *data)
{
}

static void connect_last (GtkWidget *w, void *data)
{

}

static void create_connect_server (GtkWidget *w, void *data)
{
  printf ("%s: Unimplementedn", __FUNCTION__);
}

static void do_quit (GtkWidget *w, void *data)
{
  //printf ("%s: Unimplementedn", __FUNCTION__);
  exit (0);
}

static void systray_menu (GdkEventButton *event)
{
  static GtkWidget *menu = NULL;
  GtkWidget *entry;

  if (menu) {
    gtk_widget_destroy (menu);
  }

  menu = gtk_menu_new ();

  switch (status) {
  case offline: {
    entry = gtk_menu_item_new_with_label ("Connect to last Server");
    g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (connect_last), NULL);
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), entry);
    break;
  }
  default:
    // do nothing for now
    break;
  }

  switch (status) {
  case offline:
    break;
  case online: {
    GtkWidget *systray_connect_menu;
    GSList *connect_list = NULL;
    GSList *connect_servers = NULL;    
    struct connect_server *something = NULL;

    systray_connect_menu = gtk_menu_new ();
    connect_list = connect_servers;

    while (connect_list) {

      entry = gtk_menu_item_new_with_label ("test");
      g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (connect), something);
      gtk_menu_shell_append (GTK_MENU_SHELL (systray_connect_menu), entry);

      connect_list = g_slist_next (connect_list);
    }

    if (connect_servers) {
      entry = gtk_separator_menu_item_new ();
      gtk_menu_shell_append (GTK_MENU_SHELL (systray_connect_menu), entry);
    }

    entry = gtk_menu_item_new_with_label ("New...");
    g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (create_connect_server), NULL);
    gtk_menu_shell_append (GTK_MENU_SHELL (systray_connect_menu), entry);

    break;
  }
  default:
    printf ("Uh oh, unhandled switch in %sn", __FUNCTION__);
  }

  entry = gtk_separator_menu_item_new ();
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), entry);

  entry = gtk_menu_item_new_with_label ("Quit");
  g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (do_quit), NULL);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), entry);

  gtk_widget_show_all (menu);
  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, event->time);
}

static void systray_clicked (GtkWidget *button, GdkEventButton *event, void *data)
{
  static int showing = 1;
  /*
  if (event->type != GDK_BUTTON_PRESS) {
    printf ("Ooops (%d), got something other than a button press (%s) %dn", __LINE__, __FUNCTION__,
            event->type);
  }
  */
  switch (event->button) {
  case 1: {
    GtkWidget *w;
    GtkWidgetFlags flags;
    w = (GtkWidget *)gtk_window_list_toplevels ()->data;
    if (GTK_WIDGET_VISIBLE (w)) {
      gtk_widget_hide_all (w);
    } else {
      gtk_widget_show_all (w);
    }
    break;
  }
  case 2:
    break;
  case 3:
    systray_menu (event);
    break;
  }
}

static void systray_update_icon ()
{
  const gchar *icon_name = NULL;
  
  switch (icon) {
  case offline:
    icon_name = GTK_STOCK_NO;
    break;
  case online:
    icon_name = GTK_STOCK_YES;
    break;
  default:
    printf ("Ooops unhandled switch case in %sn", __FUNCTION__);
  }

  gtk_image_set_from_stock (GTK_IMAGE (image), icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
}

static gboolean systray_update_status ()
{
  enum systray_status oldstatus;
  //enum systray_status is_online, is_offline;
  
  oldstatus = status;

  if (is_online)
    status = online;
  if (is_offline)
    status = offline;

  if (status != oldstatus) {
    icon = status;
    systray_update_icon ();
  }

  return FALSE;
}

static void systray_embedded (GtkWidget *widget, void *data)
{
  printf ("Systray: Tray icon is embedded (unimplemented)n");
  //gtk_blist_systray_add ();
}

static void systray_remove_callbacks ()
{
  printf ("Systray: Removing callbacks");

  while (g_source_remove_by_user_data (&systray)) {
    printf (".");
  }

  printf ("n");
}

static void systray_destroyed (GtkWidget *widget, void *data)
{
  printf ("Systray: Tray icon destroyedn");

  //gtk_blist_systray_remove ();
  //systray_flush_queue ();
  systray_remove_callbacks ();
  g_object_unref (G_OBJECT (systray));
  systray = NULL;
  //g_idle_add (systray_create, &systray);
}

gboolean systray_create (void)
{
  GtkWidget *box;
  if (systray) {
    /* something is screwy if this is called on an already created systray */
    printf ("Systray: Already created!n");
  }

  systray = tray_icon_new ("Test");
  box = gtk_event_box_new ();
  image = gtk_image_new ();

  g_signal_connect (G_OBJECT (systray), "embedded", G_CALLBACK (systray_embedded), NULL);
  g_signal_connect (G_OBJECT (systray), "destroy", G_CALLBACK (systray_destroyed), NULL);
  g_signal_connect (G_OBJECT (box), "button-press-event", G_CALLBACK (systray_clicked), NULL);

  gtk_container_add (GTK_CONTAINER (box), image);
  gtk_container_add (GTK_CONTAINER (systray), box);
  gtk_widget_show_all (GTK_WIDGET (systray));

  g_object_ref (G_OBJECT (systray));
  systray_update_status ();
  systray_update_icon ();

  return FALSE;
}

 

 

 

 

 

 

 

你可能感兴趣的:(manager,filter,null,Class,menu,gtk)