Blame libwnck/application.c

Packit 4e910c
/* application object */
Packit 4e910c
/* vim: set sw=2 et: */
Packit 4e910c
Packit 4e910c
/*
Packit 4e910c
 * Copyright (C) 2001 Havoc Pennington
Packit 4e910c
 * Copyright (C) 2003 Red Hat, Inc.
Packit 4e910c
 * Copyright (C) 2005-2007 Vincent Untz
Packit 4e910c
 *
Packit 4e910c
 * This library is free software; you can redistribute it and/or
Packit 4e910c
 * modify it under the terms of the GNU Library General Public
Packit 4e910c
 * License as published by the Free Software Foundation; either
Packit 4e910c
 * version 2 of the License, or (at your option) any later version.
Packit 4e910c
 *
Packit 4e910c
 * This library is distributed in the hope that it will be useful,
Packit 4e910c
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4e910c
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 4e910c
 * Library General Public License for more details.
Packit 4e910c
 *
Packit 4e910c
 * You should have received a copy of the GNU Library General Public
Packit 4e910c
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit 4e910c
 */
Packit 4e910c
Packit 4e910c
#include <config.h>
Packit 4e910c
Packit 4e910c
#include <glib/gi18n-lib.h>
Packit 4e910c
#include "application.h"
Packit 4e910c
#include "private.h"
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * SECTION:application
Packit 4e910c
 * @short_description: an object representing a group of windows of the same
Packit 4e910c
 * application.
Packit 4e910c
 * @see_also: wnck_window_get_application()
Packit 4e910c
 * @stability: Unstable
Packit 4e910c
 *
Packit 4e910c
 * The #WnckApplication is a group of #WnckWindow that are all in the same
Packit 4e910c
 * application. It can be used to represent windows by applications, group
Packit 4e910c
 * windows by applications or to manipulate all windows of a particular
Packit 4e910c
 * application.
Packit 4e910c
 *
Packit 4e910c
 * A #WnckApplication is identified by the group leader of the #WnckWindow
Packit 4e910c
 * belonging to it, and new #WnckWindow are added to a #WnckApplication if and
Packit 4e910c
 * only if they have the group leader of the #WnckApplication.
Packit 4e910c
 *
Packit 4e910c
 * The #WnckApplication objects are always owned by libwnck and must not be
Packit 4e910c
 * referenced or unreferenced.
Packit 4e910c
 */
Packit 4e910c
Packit 4e910c
#define FALLBACK_NAME _("Untitled application")
Packit 4e910c
Packit 4e910c
static GHashTable *app_hash = NULL;
Packit 4e910c
Packit 4e910c
struct _WnckApplicationPrivate
Packit 4e910c
{
Packit 4e910c
  Window xwindow; /* group leader */
Packit 4e910c
  WnckScreen *screen;
Packit 4e910c
  GList *windows;
Packit 4e910c
  int pid;
Packit 4e910c
  char *name;
Packit 4e910c
Packit 4e910c
  int orig_event_mask;
Packit 4e910c
Packit 4e910c
  WnckWindow *name_window;    /* window we are using name of */
Packit 4e910c
Packit 4e910c
  GdkPixbuf *icon;
Packit 4e910c
  GdkPixbuf *mini_icon;
Packit 4e910c
Packit 4e910c
  WnckIconCache *icon_cache;
Packit 4e910c
Packit 4e910c
  WnckWindow *icon_window;
Packit 4e910c
Packit 4e910c
  char *startup_id;
Packit 4e910c
Packit 4e910c
  guint name_from_leader : 1; /* name is from group leader */
Packit 4e910c
  guint icon_from_leader : 1;
Packit 4e910c
Packit 4e910c
  guint need_emit_icon_changed : 1;
Packit 4e910c
};
Packit 4e910c
Packit 4e910c
G_DEFINE_TYPE (WnckApplication, wnck_application, G_TYPE_OBJECT);
Packit 4e910c
#define WNCK_APPLICATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), WNCK_TYPE_APPLICATION, WnckApplicationPrivate))
Packit 4e910c
Packit 4e910c
enum {
Packit 4e910c
  NAME_CHANGED,
Packit 4e910c
  ICON_CHANGED,
Packit 4e910c
  LAST_SIGNAL
Packit 4e910c
};
Packit 4e910c
Packit 4e910c
static void emit_name_changed (WnckApplication *app);
Packit 4e910c
static void emit_icon_changed (WnckApplication *app);
Packit 4e910c
Packit 4e910c
static void reset_name  (WnckApplication *app);
Packit 4e910c
static void update_name (WnckApplication *app);
Packit 4e910c
Packit 4e910c
static void wnck_application_finalize    (GObject        *object);
Packit 4e910c
Packit 4e910c
static guint signals[LAST_SIGNAL] = { 0 };
Packit 4e910c
Packit 4e910c
void
Packit 4e910c
_wnck_application_shutdown_all (void)
Packit 4e910c
{
Packit 4e910c
  if (app_hash != NULL)
Packit 4e910c
    {
Packit 4e910c
      g_hash_table_destroy (app_hash);
Packit 4e910c
      app_hash = NULL;
Packit 4e910c
    }
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
wnck_application_init (WnckApplication *application)
Packit 4e910c
{
Packit 4e910c
  application->priv = WNCK_APPLICATION_GET_PRIVATE (application);
Packit 4e910c
Packit 4e910c
  application->priv->icon_cache = _wnck_icon_cache_new ();
Packit 4e910c
  _wnck_icon_cache_set_want_fallback (application->priv->icon_cache, FALSE);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
wnck_application_class_init (WnckApplicationClass *klass)
Packit 4e910c
{
Packit 4e910c
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit 4e910c
Packit 4e910c
  g_type_class_add_private (klass, sizeof (WnckApplicationPrivate));
Packit 4e910c
Packit 4e910c
  object_class->finalize = wnck_application_finalize;
Packit 4e910c
Packit 4e910c
  /**
Packit 4e910c
   * WnckApplication::name-changed:
Packit 4e910c
   * @app: the #WnckApplication which emitted the signal.
Packit 4e910c
   *
Packit 4e910c
   * Emitted when the name of @app changes.
Packit 4e910c
   */
Packit 4e910c
  signals[NAME_CHANGED] =
Packit 4e910c
    g_signal_new ("name_changed",
Packit 4e910c
                  G_OBJECT_CLASS_TYPE (object_class),
Packit 4e910c
                  G_SIGNAL_RUN_LAST,
Packit 4e910c
                  G_STRUCT_OFFSET (WnckApplicationClass, name_changed),
Packit 4e910c
                  NULL, NULL, NULL,
Packit 4e910c
                  G_TYPE_NONE, 0);
Packit 4e910c
Packit 4e910c
  /**
Packit 4e910c
   * WnckApplication::icon-changed:
Packit 4e910c
   * @app: the #WnckApplication which emitted the signal.
Packit 4e910c
   *
Packit 4e910c
   * Emitted when the icon of @app changes.
Packit 4e910c
   */
Packit 4e910c
  signals[ICON_CHANGED] =
Packit 4e910c
    g_signal_new ("icon_changed",
Packit 4e910c
                  G_OBJECT_CLASS_TYPE (object_class),
Packit 4e910c
                  G_SIGNAL_RUN_LAST,
Packit 4e910c
                  G_STRUCT_OFFSET (WnckApplicationClass, icon_changed),
Packit 4e910c
                  NULL, NULL, NULL,
Packit 4e910c
                  G_TYPE_NONE, 0);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
wnck_application_finalize (GObject *object)
Packit 4e910c
{
Packit 4e910c
  WnckApplication *application;
Packit 4e910c
Packit 4e910c
  application = WNCK_APPLICATION (object);
Packit 4e910c
Packit 4e910c
  _wnck_select_input (WNCK_SCREEN_XSCREEN (application->priv->screen),
Packit 4e910c
                      application->priv->xwindow,
Packit 4e910c
                      application->priv->orig_event_mask,
Packit 4e910c
                      FALSE);
Packit 4e910c
Packit 4e910c
  application->priv->xwindow = None;
Packit 4e910c
Packit 4e910c
  g_list_free (application->priv->windows);
Packit 4e910c
  application->priv->windows = NULL;
Packit 4e910c
Packit 4e910c
  g_free (application->priv->name);
Packit 4e910c
  application->priv->name = NULL;
Packit 4e910c
Packit 4e910c
  if (application->priv->icon)
Packit 4e910c
    g_object_unref (G_OBJECT (application->priv->icon));
Packit 4e910c
  application->priv->icon = NULL;
Packit 4e910c
Packit 4e910c
  if (application->priv->mini_icon)
Packit 4e910c
    g_object_unref (G_OBJECT (application->priv->mini_icon));
Packit 4e910c
  application->priv->mini_icon = NULL;
Packit 4e910c
Packit 4e910c
  _wnck_icon_cache_free (application->priv->icon_cache);
Packit 4e910c
  application->priv->icon_cache = NULL;
Packit 4e910c
Packit 4e910c
  g_free (application->priv->startup_id);
Packit 4e910c
  application->priv->startup_id = NULL;
Packit 4e910c
Packit 4e910c
  G_OBJECT_CLASS (wnck_application_parent_class)->finalize (object);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get:
Packit 4e910c
 * @xwindow: the X window ID of a group leader.
Packit 4e910c
 *
Packit 4e910c
 * Gets the #WnckApplication corresponding to the group leader with @xwindow
Packit 4e910c
 * as X window ID.
Packit 4e910c
 *
Packit 4e910c
 * Return value: (transfer none): the #WnckApplication corresponding to
Packit 4e910c
 * @xwindow, or %NULL if there no such #WnckApplication could be found. The
Packit 4e910c
 * returned #WnckApplication is owned by libwnck and must not be referenced or
Packit 4e910c
 * unreferenced.
Packit 4e910c
 */
Packit 4e910c
WnckApplication*
Packit 4e910c
wnck_application_get (gulong xwindow)
Packit 4e910c
{
Packit 4e910c
  if (app_hash == NULL)
Packit 4e910c
    return NULL;
Packit 4e910c
  else
Packit 4e910c
    return g_hash_table_lookup (app_hash, &xwindow);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get_xid:
Packit 4e910c
 * @app: a #WnckApplication.
Packit 4e910c
 *
Packit 4e910c
 * Gets the X window ID of the group leader window for @app.
Packit 4e910c
 *
Packit 4e910c
 * Return value: the X window ID of the group leader window for @app.
Packit 4e910c
 **/
Packit 4e910c
gulong
Packit 4e910c
wnck_application_get_xid (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_val_if_fail (WNCK_IS_APPLICATION (app), 0);
Packit 4e910c
Packit 4e910c
  return app->priv->xwindow;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get_windows:
Packit 4e910c
 * @app: a #WnckApplication.
Packit 4e910c
 *
Packit 4e910c
 * Gets the list of #WnckWindow belonging to @app.
Packit 4e910c
 *
Packit 4e910c
 * Return value: (element-type WnckWindow) (transfer none): the list of
Packit 4e910c
 * #WnckWindow belonging to @app, or %NULL if the application contains no
Packit 4e910c
 * window. The list should not be modified nor freed, as it is owned by @app.
Packit 4e910c
 **/
Packit 4e910c
GList*
Packit 4e910c
wnck_application_get_windows (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_val_if_fail (WNCK_IS_APPLICATION (app), NULL);
Packit 4e910c
Packit 4e910c
  return app->priv->windows;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get_n_windows:
Packit 4e910c
 * @app: a #WnckApplication.
Packit 4e910c
 *
Packit 4e910c
 * Gets the number of #WnckWindow belonging to @app.
Packit 4e910c
 *
Packit 4e910c
 * Return value: the number of #WnckWindow belonging to @app.
Packit 4e910c
 **/
Packit 4e910c
int
Packit 4e910c
wnck_application_get_n_windows (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_val_if_fail (WNCK_IS_APPLICATION (app), 0);
Packit 4e910c
Packit 4e910c
  return g_list_length (app->priv->windows);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get_name:
Packit 4e910c
 * @app: a #WnckApplication.
Packit 4e910c
 *
Packit 4e910c
 * Gets the name of @app. Since there is no way to properly find this name,
Packit 4e910c
 * various suboptimal heuristics are used to find it. GTK+ should probably have
Packit 4e910c
 * a function to allow applications to set the _NET_WM_NAME property on the
Packit 4e910c
 * group leader as the application name, and the 
Packit 4e910c
 * url="http://standards.freedesktop.org/wm-spec/wm-spec-latest.html">EWMH</ulink>
Packit 4e910c
 * should say that this is where the application name goes.
Packit 4e910c
 *
Packit 4e910c
 * Return value: the name of @app, or a fallback name if no name is available.
Packit 4e910c
 **/
Packit 4e910c
const char*
Packit 4e910c
wnck_application_get_name (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_val_if_fail (WNCK_IS_APPLICATION (app), NULL);
Packit 4e910c
Packit 4e910c
  if (app->priv->name)
Packit 4e910c
    return app->priv->name;
Packit 4e910c
  else
Packit 4e910c
    return FALLBACK_NAME;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get_icon_name:
Packit 4e910c
 * @app: a #WnckApplication
Packit 4e910c
 *
Packit 4e910c
 * Gets the icon name of @app (to be used when @app is minimized). Since
Packit 4e910c
 * there is no way to properly find this name, various suboptimal heuristics
Packit 4e910c
 * are used to find it.
Packit 4e910c
 *
Packit 4e910c
 * Return value: the icon name of @app, or a fallback icon name if no icon name
Packit 4e910c
 * is available.
Packit 4e910c
 **/
Packit 4e910c
const char*
Packit 4e910c
wnck_application_get_icon_name (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_val_if_fail (WNCK_IS_APPLICATION (app), NULL);
Packit 4e910c
Packit 4e910c
  /* FIXME this isn't actually implemented, should be different
Packit 4e910c
   * from regular name
Packit 4e910c
   */
Packit 4e910c
Packit 4e910c
  if (app->priv->name)
Packit 4e910c
    return app->priv->name;
Packit 4e910c
  else
Packit 4e910c
    return FALLBACK_NAME;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get_pid:
Packit 4e910c
 * @app: a #WnckApplication.
Packit 4e910c
 *
Packit 4e910c
 * Gets the process ID of @app.
Packit 4e910c
 *
Packit 4e910c
 * Return value: the process ID of @app, or 0 if none is available.
Packit 4e910c
 **/
Packit 4e910c
int
Packit 4e910c
wnck_application_get_pid (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_val_if_fail (WNCK_IS_APPLICATION (app), 0);
Packit 4e910c
Packit 4e910c
  return app->priv->pid;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
get_icons (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  GdkPixbuf *icon;
Packit 4e910c
  GdkPixbuf *mini_icon;
Packit 4e910c
  gsize normal_size;
Packit 4e910c
  gsize mini_size;
Packit 4e910c
Packit 4e910c
  icon = NULL;
Packit 4e910c
  mini_icon = NULL;
Packit 4e910c
  normal_size = _wnck_get_default_icon_size ();
Packit 4e910c
  mini_size = _wnck_get_default_mini_icon_size ();
Packit 4e910c
Packit 4e910c
  if (_wnck_read_icons (WNCK_SCREEN_XSCREEN (app->priv->screen),
Packit 4e910c
                        app->priv->xwindow,
Packit 4e910c
                        app->priv->icon_cache,
Packit 4e910c
                        &icon, normal_size, normal_size,
Packit 4e910c
                        &mini_icon, mini_size, mini_size))
Packit 4e910c
    {
Packit 4e910c
      app->priv->need_emit_icon_changed = TRUE;
Packit 4e910c
      app->priv->icon_from_leader = TRUE;
Packit 4e910c
Packit 4e910c
      if (app->priv->icon)
Packit 4e910c
        g_object_unref (G_OBJECT (app->priv->icon));
Packit 4e910c
Packit 4e910c
      if (app->priv->mini_icon)
Packit 4e910c
        g_object_unref (G_OBJECT (app->priv->mini_icon));
Packit 4e910c
Packit 4e910c
      app->priv->icon = icon;
Packit 4e910c
      app->priv->mini_icon = mini_icon;
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  /* FIXME we should really fall back to using the icon
Packit 4e910c
   * for one of the windows. But then we need to be more
Packit 4e910c
   * complicated about icon_changed and when the icon
Packit 4e910c
   * needs updating and all that.
Packit 4e910c
   */
Packit 4e910c
Packit 4e910c
  g_assert ((app->priv->icon && app->priv->mini_icon) ||
Packit 4e910c
            !(app->priv->icon || app->priv->mini_icon));
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
void
Packit 4e910c
_wnck_application_load_icons (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_if_fail (WNCK_IS_APPLICATION (app));
Packit 4e910c
Packit 4e910c
  get_icons (app);
Packit 4e910c
  if (app->priv->need_emit_icon_changed)
Packit 4e910c
    emit_icon_changed (app);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/* Prefer to get group icon from a window of type "normal" */
Packit 4e910c
static WnckWindow*
Packit 4e910c
find_icon_window (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  GList *tmp;
Packit 4e910c
Packit 4e910c
  tmp = app->priv->windows;
Packit 4e910c
  while (tmp != NULL)
Packit 4e910c
    {
Packit 4e910c
      WnckWindow *w = tmp->data;
Packit 4e910c
Packit 4e910c
      if (wnck_window_get_window_type (w) == WNCK_WINDOW_NORMAL)
Packit 4e910c
        return w;
Packit 4e910c
Packit 4e910c
      tmp = tmp->next;
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  if (app->priv->windows)
Packit 4e910c
    return app->priv->windows->data;
Packit 4e910c
  else
Packit 4e910c
    return NULL;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get_icon:
Packit 4e910c
 * @app: a #WnckApplication.
Packit 4e910c
 *
Packit 4e910c
 * Gets the icon to be used for @app. If no icon is set for @app, a
Packit 4e910c
 * suboptimal heuristic is used to find an appropriate icon. If no icon was
Packit 4e910c
 * found, a fallback icon is used.
Packit 4e910c
 *
Packit 4e910c
 * Return value: (transfer none): the icon for @app. The caller should
Packit 4e910c
 * reference the returned <classname>GdkPixbuf</classname> if it needs to keep
Packit 4e910c
 * the icon around.
Packit 4e910c
 **/
Packit 4e910c
GdkPixbuf*
Packit 4e910c
wnck_application_get_icon (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_val_if_fail (WNCK_IS_APPLICATION (app), NULL);
Packit 4e910c
Packit 4e910c
  _wnck_application_load_icons (app);
Packit 4e910c
Packit 4e910c
  if (app->priv->icon)
Packit 4e910c
    return app->priv->icon;
Packit 4e910c
  else
Packit 4e910c
    {
Packit 4e910c
      WnckWindow *w = find_icon_window (app);
Packit 4e910c
      if (w)
Packit 4e910c
        return wnck_window_get_icon (w);
Packit 4e910c
      else
Packit 4e910c
        return NULL;
Packit 4e910c
    }
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get_mini_icon:
Packit 4e910c
 * @app: a #WnckApplication.
Packit 4e910c
 *
Packit 4e910c
 * Gets the mini-icon to be used for @app. If no mini-icon is set for @app,
Packit 4e910c
 * a suboptimal heuristic is used to find an appropriate icon. If no mini-icon
Packit 4e910c
 * was found, a fallback mini-icon is used.
Packit 4e910c
 *
Packit 4e910c
 * Return value: (transfer none): the mini-icon for @app. The caller should
Packit 4e910c
 * reference the returned <classname>GdkPixbuf</classname> if it needs to keep
Packit 4e910c
 * the mini-icon around.
Packit 4e910c
 **/
Packit 4e910c
GdkPixbuf*
Packit 4e910c
wnck_application_get_mini_icon (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_val_if_fail (WNCK_IS_APPLICATION (app), NULL);
Packit 4e910c
Packit 4e910c
  _wnck_application_load_icons (app);
Packit 4e910c
Packit 4e910c
  if (app->priv->mini_icon)
Packit 4e910c
    return app->priv->mini_icon;
Packit 4e910c
  else
Packit 4e910c
    {
Packit 4e910c
      WnckWindow *w = find_icon_window (app);
Packit 4e910c
      if (w)
Packit 4e910c
        return wnck_window_get_mini_icon (w);
Packit 4e910c
      else
Packit 4e910c
        return NULL;
Packit 4e910c
    }
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get_icon_is_fallback:
Packit 4e910c
 * @app: a #WnckApplication
Packit 4e910c
 *
Packit 4e910c
 * Gets whether a default fallback icon is used for @app (because none
Packit 4e910c
 * was set on @app).
Packit 4e910c
 *
Packit 4e910c
 * Return value: %TRUE if the icon for @app is a fallback, %FALSE otherwise.
Packit 4e910c
 **/
Packit 4e910c
gboolean
Packit 4e910c
wnck_application_get_icon_is_fallback (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_val_if_fail (WNCK_IS_APPLICATION (app), FALSE);
Packit 4e910c
Packit 4e910c
  if (app->priv->icon)
Packit 4e910c
    return FALSE;
Packit 4e910c
  else
Packit 4e910c
    {
Packit 4e910c
      WnckWindow *w = find_icon_window (app);
Packit 4e910c
      if (w)
Packit 4e910c
        return wnck_window_get_icon_is_fallback (w);
Packit 4e910c
      else
Packit 4e910c
        return TRUE;
Packit 4e910c
    }
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_application_get_startup_id:
Packit 4e910c
 * @app: a #WnckApplication.
Packit 4e910c
 *
Packit 4e910c
 * Gets the startup sequence ID used for startup notification of @app.
Packit 4e910c
 *
Packit 4e910c
 * Return value: the startup sequence ID used for startup notification of @app,
Packit 4e910c
 * or %NULL if none is available.
Packit 4e910c
 *
Packit 4e910c
 * Since: 2.2
Packit 4e910c
 */
Packit 4e910c
const char*
Packit 4e910c
wnck_application_get_startup_id (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_return_val_if_fail (WNCK_IS_APPLICATION (app), NULL);
Packit 4e910c
Packit 4e910c
  return app->priv->startup_id;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/* xwindow is a group leader */
Packit 4e910c
WnckApplication*
Packit 4e910c
_wnck_application_create (Window      xwindow,
Packit 4e910c
                          WnckScreen *screen)
Packit 4e910c
{
Packit 4e910c
  WnckApplication *application;
Packit 4e910c
  Screen          *xscreen;
Packit 4e910c
Packit 4e910c
  if (app_hash == NULL)
Packit 4e910c
    app_hash = g_hash_table_new_full (_wnck_xid_hash, _wnck_xid_equal,
Packit 4e910c
                                      NULL, g_object_unref);
Packit 4e910c
Packit 4e910c
  g_return_val_if_fail (g_hash_table_lookup (app_hash, &xwindow) == NULL,
Packit 4e910c
                        NULL);
Packit 4e910c
Packit 4e910c
  xscreen = WNCK_SCREEN_XSCREEN (screen);
Packit 4e910c
Packit 4e910c
  application = g_object_new (WNCK_TYPE_APPLICATION, NULL);
Packit 4e910c
  application->priv->xwindow = xwindow;
Packit 4e910c
  application->priv->screen = screen;
Packit 4e910c
Packit 4e910c
  application->priv->name = _wnck_get_name (xscreen, xwindow);
Packit 4e910c
Packit 4e910c
  if (application->priv->name == NULL)
Packit 4e910c
    application->priv->name = _wnck_get_res_class_utf8 (xscreen, xwindow);
Packit 4e910c
Packit 4e910c
  if (application->priv->name)
Packit 4e910c
    application->priv->name_from_leader = TRUE;
Packit 4e910c
Packit 4e910c
  application->priv->pid = _wnck_get_pid (xscreen,
Packit 4e910c
                                          application->priv->xwindow);
Packit 4e910c
Packit 4e910c
  application->priv->startup_id = _wnck_get_utf8_property (xscreen,
Packit 4e910c
                                                           application->priv->xwindow,
Packit 4e910c
                                                           _wnck_atom_get ("_NET_STARTUP_ID"));
Packit 4e910c
Packit 4e910c
  g_hash_table_insert (app_hash, &application->priv->xwindow, application);
Packit 4e910c
Packit 4e910c
  /* Hash now owns one ref, caller gets none */
Packit 4e910c
Packit 4e910c
  /* Note that xwindow may correspond to a WnckWindow's xwindow,
Packit 4e910c
   * so we select events needed by either
Packit 4e910c
   */
Packit 4e910c
  application->priv->orig_event_mask = _wnck_select_input (xscreen,
Packit 4e910c
                                                           application->priv->xwindow,
Packit 4e910c
                                                           WNCK_APP_WINDOW_EVENT_MASK,
Packit 4e910c
                                                           TRUE);
Packit 4e910c
Packit 4e910c
  return application;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
void
Packit 4e910c
_wnck_application_destroy (WnckApplication *application)
Packit 4e910c
{
Packit 4e910c
  Window xwindow = application->priv->xwindow;
Packit 4e910c
Packit 4e910c
  g_return_if_fail (wnck_application_get (xwindow) == application);
Packit 4e910c
Packit 4e910c
  g_hash_table_remove (app_hash, &xwindow);
Packit 4e910c
Packit 4e910c
  /* Removing from hash also removes the only ref WnckApplication had */
Packit 4e910c
Packit 4e910c
  g_return_if_fail (wnck_application_get (xwindow) == NULL);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
window_name_changed (WnckWindow      *window,
Packit 4e910c
                     WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  if (window == app->priv->name_window)
Packit 4e910c
    {
Packit 4e910c
      reset_name (app);
Packit 4e910c
      update_name (app);
Packit 4e910c
    }
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
void
Packit 4e910c
_wnck_application_add_window (WnckApplication *app,
Packit 4e910c
                              WnckWindow      *window)
Packit 4e910c
{
Packit 4e910c
  g_return_if_fail (WNCK_IS_APPLICATION (app));
Packit 4e910c
  g_return_if_fail (WNCK_IS_WINDOW (window));
Packit 4e910c
  g_return_if_fail (wnck_window_get_application (window) == NULL);
Packit 4e910c
Packit 4e910c
  app->priv->windows = g_list_prepend (app->priv->windows, window);
Packit 4e910c
  _wnck_window_set_application (window, app);
Packit 4e910c
Packit 4e910c
  g_signal_connect (G_OBJECT (window), "name_changed",
Packit 4e910c
                    G_CALLBACK (window_name_changed), app);
Packit 4e910c
Packit 4e910c
  /* emits signals, so do it last */
Packit 4e910c
  reset_name (app);
Packit 4e910c
  update_name (app);
Packit 4e910c
Packit 4e910c
  /* see if we're using icon from a window */
Packit 4e910c
  if (app->priv->icon == NULL ||
Packit 4e910c
      app->priv->mini_icon == NULL)
Packit 4e910c
    emit_icon_changed (app);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
void
Packit 4e910c
_wnck_application_remove_window (WnckApplication *app,
Packit 4e910c
                                 WnckWindow      *window)
Packit 4e910c
{
Packit 4e910c
  g_return_if_fail (WNCK_IS_APPLICATION (app));
Packit 4e910c
  g_return_if_fail (WNCK_IS_WINDOW (window));
Packit 4e910c
  g_return_if_fail (wnck_window_get_application (window) == app);
Packit 4e910c
Packit 4e910c
  app->priv->windows = g_list_remove (app->priv->windows, window);
Packit 4e910c
  _wnck_window_set_application (window, NULL);
Packit 4e910c
Packit 4e910c
  g_signal_handlers_disconnect_by_func (G_OBJECT (window),
Packit 4e910c
                                        window_name_changed, app);
Packit 4e910c
Packit 4e910c
  /* emits signals, so do it last */
Packit 4e910c
  reset_name (app);
Packit 4e910c
  update_name (app);
Packit 4e910c
Packit 4e910c
  /* see if we're using icon from a window */
Packit 4e910c
  if (app->priv->icon == NULL ||
Packit 4e910c
      app->priv->mini_icon == NULL)
Packit 4e910c
    emit_icon_changed (app);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
void
Packit 4e910c
_wnck_application_process_property_notify (WnckApplication *app,
Packit 4e910c
                                           XEvent          *xevent)
Packit 4e910c
{
Packit 4e910c
  /* This prop notify is on the leader window */
Packit 4e910c
Packit 4e910c
  if (xevent->xproperty.atom == XA_WM_NAME ||
Packit 4e910c
      xevent->xproperty.atom ==
Packit 4e910c
      _wnck_atom_get ("_NET_WM_NAME") ||
Packit 4e910c
      xevent->xproperty.atom ==
Packit 4e910c
      _wnck_atom_get ("_NET_WM_VISIBLE_NAME"))
Packit 4e910c
    {
Packit 4e910c
      /* FIXME should change the name */
Packit 4e910c
    }
Packit 4e910c
  else if (xevent->xproperty.atom ==
Packit 4e910c
           XA_WM_ICON_NAME ||
Packit 4e910c
           xevent->xproperty.atom ==
Packit 4e910c
           _wnck_atom_get ("_NET_WM_ICON_NAME") ||
Packit 4e910c
           xevent->xproperty.atom ==
Packit 4e910c
           _wnck_atom_get ("_NET_WM_VISIBLE_ICON_NAME"))
Packit 4e910c
    {
Packit 4e910c
      /* FIXME */
Packit 4e910c
    }
Packit 4e910c
  else if (xevent->xproperty.atom ==
Packit 4e910c
           _wnck_atom_get ("_NET_WM_ICON") ||
Packit 4e910c
           xevent->xproperty.atom ==
Packit 4e910c
           _wnck_atom_get ("KWM_WIN_ICON") ||
Packit 4e910c
           xevent->xproperty.atom ==
Packit 4e910c
           _wnck_atom_get ("WM_NORMAL_HINTS"))
Packit 4e910c
    {
Packit 4e910c
      _wnck_icon_cache_property_changed (app->priv->icon_cache,
Packit 4e910c
                                         xevent->xproperty.atom);
Packit 4e910c
      emit_icon_changed (app);
Packit 4e910c
    }
Packit 4e910c
  else if (xevent->xproperty.atom ==
Packit 4e910c
           _wnck_atom_get ("_NET_STARTUP_ID"))
Packit 4e910c
    {
Packit 4e910c
      /* FIXME update startup id */
Packit 4e910c
    }
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
emit_name_changed (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_signal_emit (G_OBJECT (app),
Packit 4e910c
                 signals[NAME_CHANGED],
Packit 4e910c
                 0);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
emit_icon_changed (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  app->priv->need_emit_icon_changed = FALSE;
Packit 4e910c
  g_signal_emit (G_OBJECT (app),
Packit 4e910c
                 signals[ICON_CHANGED],
Packit 4e910c
                 0);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
reset_name  (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  if (!app->priv->name_from_leader)
Packit 4e910c
    {
Packit 4e910c
      g_free (app->priv->name);
Packit 4e910c
      app->priv->name = NULL;
Packit 4e910c
      app->priv->name_window = NULL;
Packit 4e910c
    }
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
update_name (WnckApplication *app)
Packit 4e910c
{
Packit 4e910c
  g_assert (app->priv->name_from_leader || app->priv->name == NULL);
Packit 4e910c
Packit 4e910c
  if (app->priv->name == NULL)
Packit 4e910c
    {
Packit 4e910c
      /* if only one window, get name from there. If more than one and
Packit 4e910c
       * they all have the same res_class, use that. Else we want to
Packit 4e910c
       * use the fallback name, since using the title of one of the
Packit 4e910c
       * windows would look wrong.
Packit 4e910c
       */
Packit 4e910c
      if (app->priv->windows &&
Packit 4e910c
          app->priv->windows->next == NULL)
Packit 4e910c
        {
Packit 4e910c
          app->priv->name =
Packit 4e910c
            g_strdup (wnck_window_get_name (app->priv->windows->data));
Packit 4e910c
          app->priv->name_window = app->priv->windows->data;
Packit 4e910c
          emit_name_changed (app);
Packit 4e910c
        }
Packit 4e910c
      else if (app->priv->windows)
Packit 4e910c
        {
Packit 4e910c
          /* more than one */
Packit 4e910c
          app->priv->name =
Packit 4e910c
            _wnck_get_res_class_utf8 (WNCK_SCREEN_XSCREEN (app->priv->screen),
Packit 4e910c
                                      wnck_window_get_xid (app->priv->windows->data));
Packit 4e910c
          if (app->priv->name)
Packit 4e910c
            {
Packit 4e910c
              app->priv->name_window = app->priv->windows->data;
Packit 4e910c
              emit_name_changed (app);
Packit 4e910c
            }
Packit 4e910c
        }
Packit 4e910c
    }
Packit 4e910c
}