Blame libgnomekbd/gkbd-status.c

Packit 88888e
/*
Packit 88888e
 * Copyright (C) 2006 Sergey V. Udaltsov <svu@gnome.org>
Packit 88888e
 *
Packit 88888e
 * This library is free software; you can redistribute it and/or
Packit 88888e
 * modify it under the terms of the GNU Lesser General Public
Packit 88888e
 * License as published by the Free Software Foundation; either
Packit 88888e
 * version 2 of the License, or (at your option) any later version.
Packit 88888e
 *
Packit 88888e
 * This library is distributed in the hope that it will be useful,
Packit 88888e
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 88888e
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 88888e
 * Lesser General Public License for more details.
Packit 88888e
 *
Packit 88888e
 * You should have received a copy of the GNU Lesser General Public
Packit 88888e
 * License along with this library; if not, write to the
Packit 88888e
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 88888e
 * Boston, MA 02111-1307, USA.
Packit 88888e
 */
Packit 88888e
#include <config.h>
Packit 88888e
Packit 88888e
#include <memory.h>
Packit 88888e
Packit 88888e
#include <cairo.h>
Packit 88888e
Packit 88888e
#include <gdk/gdkkeysyms.h>
Packit 88888e
#include <gdk/gdkx.h>
Packit 88888e
#include <glib/gi18n-lib.h>
Packit 88888e
Packit 88888e
#include <gkbd-status.h>
Packit 88888e
Packit 88888e
#include <gkbd-desktop-config.h>
Packit 88888e
#include <gkbd-indicator-config.h>
Packit 88888e
#include <gkbd-configuration.h>
Packit 88888e
Packit 88888e
typedef struct _gki_globals {
Packit 88888e
	GkbdConfiguration *config;
Packit 88888e
Packit 88888e
	gint current_width;
Packit 88888e
	gint current_height;
Packit 88888e
	int real_width;
Packit 88888e
Packit 88888e
	GSList *icons;		/* list of GdkPixbuf */
Packit 88888e
} gki_globals;
Packit 88888e
Packit 88888e
static gchar *settings_signal_names[] = {
Packit 88888e
	"notify::gtk-theme-name",
Packit 88888e
	"notify::gtk-key-theme-name",
Packit 88888e
	"notify::gtk-font-name",
Packit 88888e
	"notify::font-options",
Packit 88888e
};
Packit 88888e
Packit 88888e
struct _GkbdStatusPrivate {
Packit 88888e
	gulong settings_signal_handlers[sizeof (settings_signal_names) /
Packit 88888e
					sizeof (settings_signal_names[0])];
Packit 88888e
};
Packit 88888e
Packit 88888e
/* one instance for ALL widgets */
Packit 88888e
static gki_globals globals;
Packit 88888e
Packit 88888e
G_DEFINE_TYPE (GkbdStatus, gkbd_status, GTK_TYPE_STATUS_ICON)
Packit 88888e
Packit 88888e
typedef struct {
Packit 88888e
	GtkWidget *tray_icon;
Packit 88888e
} GkbdStatusPrivHack;
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_global_init (void);
Packit 88888e
static void
Packit 88888e
gkbd_status_global_term (void);
Packit 88888e
static GdkPixbuf *
Packit 88888e
gkbd_status_prepare_drawing (GkbdStatus * gki, int group);
Packit 88888e
static void
Packit 88888e
gkbd_status_set_current_page_for_group (GkbdStatus * gki, int group);
Packit 88888e
static void
Packit 88888e
gkbd_status_set_current_page (GkbdStatus * gki);
Packit 88888e
static void
Packit 88888e
gkbd_status_reinit_globals (GkbdStatus * gki);
Packit 88888e
static void
Packit 88888e
gkbd_status_cleanup_icons (void);
Packit 88888e
static void
Packit 88888e
gkbd_status_fill_icons (GkbdStatus * gki);
Packit 88888e
static void
Packit 88888e
gkbd_status_set_tooltips (GkbdStatus * gki, const char *str);
Packit 88888e
Packit 88888e
void
Packit 88888e
gkbd_status_set_tooltips (GkbdStatus * gki, const char *str)
Packit 88888e
{
Packit 88888e
	g_assert (str == NULL || g_utf8_validate (str, -1, NULL));
Packit 88888e
Packit 88888e
	gtk_status_icon_set_tooltip_text (GTK_STATUS_ICON (gki), str);
Packit 88888e
}
Packit 88888e
Packit 88888e
void
Packit 88888e
gkbd_status_cleanup_icons ()
Packit 88888e
{
Packit 88888e
	while (globals.icons) {
Packit 88888e
		if (globals.icons->data)
Packit 88888e
			g_object_unref (G_OBJECT (globals.icons->data));
Packit 88888e
		globals.icons =
Packit 88888e
		    g_slist_delete_link (globals.icons, globals.icons);
Packit 88888e
	}
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_fill_icons (GkbdStatus * gki)
Packit 88888e
{
Packit 88888e
	int grp;
Packit 88888e
	int total_groups =
Packit 88888e
	    xkl_engine_get_num_groups (gkbd_configuration_get_xkl_engine
Packit 88888e
				       (globals.config));
Packit 88888e
Packit 88888e
	for (grp = 0; grp < total_groups; grp++) {
Packit 88888e
		GdkPixbuf *page = gkbd_status_prepare_drawing (gki, grp);
Packit 88888e
		globals.icons = g_slist_append (globals.icons, page);
Packit 88888e
	}
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_activate (GkbdStatus * gki)
Packit 88888e
{
Packit 88888e
	xkl_debug (150, "Mouse button pressed on applet\n");
Packit 88888e
	gkbd_configuration_lock_next_group (globals.config);
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_render_cairo (GkbdStatusPrivHack * gkh, cairo_t * cr, int group)
Packit 88888e
{
Packit 88888e
	double r, g, b;
Packit 88888e
	GdkRGBA *fg_color;
Packit 88888e
	gchar *font_family;
Packit 88888e
	int font_size;
Packit 88888e
	PangoFontDescription *pfd;
Packit 88888e
	PangoContext *pcc;
Packit 88888e
	PangoLayout *pl;
Packit 88888e
	int lwidth, lheight;
Packit 88888e
	gchar *layout_name, *lbl_title;
Packit 88888e
	cairo_font_options_t *fo;
Packit 88888e
	static GHashTable *ln2cnt_map = NULL;
Packit 88888e
Packit 88888e
	GkbdIndicatorConfig *ind_cfg =
Packit 88888e
	    gkbd_configuration_get_indicator_config (globals.config);
Packit 88888e
Packit 88888e
	xkl_debug (160, "Rendering cairo for group %d\n", group);
Packit 88888e
	if (ind_cfg->background_color != NULL &&
Packit 88888e
	    ind_cfg->background_color[0] != 0) {
Packit 88888e
		if (sscanf
Packit 88888e
		    (ind_cfg->background_color, "%lg %lg %lg", &r,
Packit 88888e
		     &g, &b) == 3) {
Packit 88888e
			cairo_set_source_rgb (cr, r, g, b);
Packit 88888e
			cairo_rectangle (cr, 0, 0, globals.current_width,
Packit 88888e
					 globals.current_height);
Packit 88888e
			cairo_fill (cr);
Packit 88888e
		}
Packit 88888e
	}
Packit 88888e
Packit 88888e
	g_object_get (gkh->tray_icon, "fg-color", &fg_color, NULL);
Packit 88888e
	cairo_set_source_rgb (cr, fg_color->red, fg_color->green, fg_color->blue);
Packit 88888e
	gdk_rgba_free (fg_color);
Packit 88888e
Packit 88888e
	gkbd_indicator_config_get_font_for_widget (ind_cfg,
Packit 88888e
						   gkh->tray_icon,
Packit 88888e
						   &font_family,
Packit 88888e
						   &font_size);
Packit 88888e
Packit 88888e
	if (font_family != NULL && font_family[0] != 0) {
Packit 88888e
		cairo_select_font_face (cr, font_family,
Packit 88888e
					CAIRO_FONT_SLANT_NORMAL,
Packit 88888e
					CAIRO_FONT_WEIGHT_NORMAL);
Packit 88888e
	}
Packit 88888e
Packit 88888e
	pfd = pango_font_description_new ();
Packit 88888e
	pango_font_description_set_family (pfd, font_family);
Packit 88888e
	pango_font_description_set_style (pfd, PANGO_STYLE_NORMAL);
Packit 88888e
	pango_font_description_set_weight (pfd, PANGO_WEIGHT_NORMAL);
Packit 88888e
	pango_font_description_set_size (pfd,
Packit 88888e
					 ind_cfg->font_size * PANGO_SCALE);
Packit 88888e
Packit 88888e
	g_free (font_family);
Packit 88888e
Packit 88888e
	pcc = pango_cairo_create_context (cr);
Packit 88888e
Packit 88888e
	fo = cairo_font_options_copy (gdk_screen_get_font_options
Packit 88888e
				      (gdk_screen_get_default ()));
Packit 88888e
	/* SUBPIXEL antialiasing gives bad results on in-memory images */
Packit 88888e
	if (cairo_font_options_get_antialias (fo) ==
Packit 88888e
	    CAIRO_ANTIALIAS_SUBPIXEL)
Packit 88888e
		cairo_font_options_set_antialias (fo,
Packit 88888e
						  CAIRO_ANTIALIAS_GRAY);
Packit 88888e
	pango_cairo_context_set_font_options (pcc, fo);
Packit 88888e
Packit 88888e
	pl = pango_layout_new (pcc);
Packit 88888e
Packit 88888e
	layout_name =
Packit 88888e
	    gkbd_configuration_extract_layout_name (globals.config, group);
Packit 88888e
	lbl_title =
Packit 88888e
	    gkbd_configuration_create_label_title (group, &ln2cnt_map,
Packit 88888e
						   layout_name);
Packit 88888e
Packit 88888e
	if (group + 1 ==
Packit 88888e
	    xkl_engine_get_num_groups (gkbd_configuration_get_xkl_engine
Packit 88888e
				       (globals.config))) {
Packit 88888e
		g_hash_table_destroy (ln2cnt_map);
Packit 88888e
		ln2cnt_map = NULL;
Packit 88888e
	}
Packit 88888e
Packit 88888e
	pango_layout_set_text (pl, lbl_title, -1);
Packit 88888e
Packit 88888e
	g_free (lbl_title);
Packit 88888e
Packit 88888e
	pango_layout_set_font_description (pl, pfd);
Packit 88888e
	pango_layout_get_size (pl, &lwidth, &lheight);
Packit 88888e
Packit 88888e
	cairo_move_to (cr,
Packit 88888e
		       (globals.current_width - lwidth / PANGO_SCALE) / 2,
Packit 88888e
		       (globals.current_height -
Packit 88888e
			lheight / PANGO_SCALE) / 2);
Packit 88888e
Packit 88888e
	pango_cairo_show_layout (cr, pl);
Packit 88888e
Packit 88888e
	pango_font_description_free (pfd);
Packit 88888e
	g_object_unref (pl);
Packit 88888e
	g_object_unref (pcc);
Packit 88888e
	cairo_font_options_destroy (fo);
Packit 88888e
	cairo_destroy (cr);
Packit 88888e
Packit 88888e
	globals.real_width = (lwidth / PANGO_SCALE) + 4;
Packit 88888e
	if (globals.real_width > globals.current_width)
Packit 88888e
		globals.real_width = globals.current_width;
Packit 88888e
	if (globals.real_width < globals.current_height)
Packit 88888e
		globals.real_width = globals.current_height;
Packit 88888e
}
Packit 88888e
Packit 88888e
static inline guint8
Packit 88888e
convert_color_channel (guint8 src, guint8 alpha)
Packit 88888e
{
Packit 88888e
	return alpha ? ((((guint) src) << 8) - src) / alpha : 0;
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
convert_bgra_to_rgba (guint8 const *src, guint8 * dst, int width,
Packit 88888e
		      int height, int new_width)
Packit 88888e
{
Packit 88888e
	int xoffset = width - new_width;
Packit 88888e
Packit 88888e
	/* *4 */
Packit 88888e
	int ptr_step = xoffset << 2;
Packit 88888e
Packit 88888e
	int x, y;
Packit 88888e
Packit 88888e
	/* / 2 * 4 */
Packit 88888e
	src = src + ((xoffset >> 1) << 2);
Packit 88888e
Packit 88888e
	for (y = height; --y >= 0; src += ptr_step) {
Packit 88888e
		for (x = new_width; --x >= 0;) {
Packit 88888e
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
Packit 88888e
			dst[0] = convert_color_channel (src[2], src[3]);
Packit 88888e
			dst[1] = convert_color_channel (src[1], src[3]);
Packit 88888e
			dst[2] = convert_color_channel (src[0], src[3]);
Packit 88888e
			dst[3] = src[3];
Packit 88888e
#else
Packit 88888e
			dst[0] = convert_color_channel (src[1], src[0]);
Packit 88888e
			dst[1] = convert_color_channel (src[2], src[0]);
Packit 88888e
			dst[2] = convert_color_channel (src[3], src[0]);
Packit 88888e
			dst[3] = src[0];
Packit 88888e
#endif
Packit 88888e
			dst += 4;
Packit 88888e
			src += 4;
Packit 88888e
		}
Packit 88888e
	}
Packit 88888e
}
Packit 88888e
Packit 88888e
static GdkPixbuf *
Packit 88888e
gkbd_status_prepare_drawing (GkbdStatus * gki, int group)
Packit 88888e
{
Packit 88888e
	GError *gerror = NULL;
Packit 88888e
	char *image_filename;
Packit 88888e
	GdkPixbuf *image;
Packit 88888e
Packit 88888e
	if (globals.current_width == 0)
Packit 88888e
		return NULL;
Packit 88888e
Packit 88888e
	if (gkbd_configuration_if_flags_shown (globals.config)) {
Packit 88888e
Packit 88888e
		image_filename =
Packit 88888e
		    gkbd_configuration_get_image_filename (globals.config,
Packit 88888e
							   group);
Packit 88888e
Packit 88888e
		image = gdk_pixbuf_new_from_file_at_size (image_filename,
Packit 88888e
							  globals.current_width,
Packit 88888e
							  globals.current_height,
Packit 88888e
							  &gerror);
Packit 88888e
Packit 88888e
		if (image == NULL) {
Packit 88888e
			GtkWidget *dialog = gtk_message_dialog_new (NULL,
Packit 88888e
								    GTK_DIALOG_DESTROY_WITH_PARENT,
Packit 88888e
								    GTK_MESSAGE_ERROR,
Packit 88888e
								    GTK_BUTTONS_OK,
Packit 88888e
								    _
Packit 88888e
								    ("There was an error loading an image: %s"),
Packit 88888e
								    gerror
Packit 88888e
								    ==
Packit 88888e
								    NULL ?
Packit 88888e
								    "Unknown"
Packit 88888e
								    :
Packit 88888e
								    gerror->message);
Packit 88888e
			g_signal_connect (G_OBJECT (dialog), "response",
Packit 88888e
					  G_CALLBACK (gtk_widget_destroy),
Packit 88888e
					  NULL);
Packit 88888e
Packit 88888e
			gtk_window_set_resizable (GTK_WINDOW (dialog),
Packit 88888e
						  FALSE);
Packit 88888e
Packit 88888e
			gtk_widget_show (dialog);
Packit 88888e
			g_error_free (gerror);
Packit 88888e
Packit 88888e
			return NULL;
Packit 88888e
		}
Packit 88888e
		xkl_debug (150,
Packit 88888e
			   "Image %d[%s] loaded -> %p[%dx%d], alpha: %d\n",
Packit 88888e
			   group, image_filename, image,
Packit 88888e
			   gdk_pixbuf_get_width (image),
Packit 88888e
			   gdk_pixbuf_get_height (image),
Packit 88888e
			   gdk_pixbuf_get_has_alpha (image));
Packit 88888e
Packit 88888e
		return image;
Packit 88888e
	} else {
Packit 88888e
		cairo_surface_t *cs =
Packit 88888e
		    cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
Packit 88888e
						globals.current_width,
Packit 88888e
						globals.current_height);
Packit 88888e
		unsigned char *cairo_data;
Packit 88888e
		guchar *pixbuf_data;
Packit 88888e
		gkbd_status_render_cairo ((GkbdStatusPrivHack *) GTK_STATUS_ICON (gki)->priv,
Packit 88888e
					  cairo_create (cs), group);
Packit 88888e
		cairo_data = cairo_image_surface_get_data (cs);
Packit 88888e
#if 0
Packit 88888e
		char pngfilename[20];
Packit 88888e
		g_sprintf (pngfilename, "label%d.png", group);
Packit 88888e
		cairo_surface_write_to_png (cs, pngfilename);
Packit 88888e
		xkl_debug (150, "file %s is created\n", pngfilename);
Packit 88888e
#endif
Packit 88888e
		pixbuf_data =
Packit 88888e
		    g_new0 (guchar,
Packit 88888e
			    4 * globals.real_width *
Packit 88888e
			    globals.current_height);
Packit 88888e
		convert_bgra_to_rgba (cairo_data, pixbuf_data,
Packit 88888e
				      globals.current_width,
Packit 88888e
				      globals.current_height,
Packit 88888e
				      globals.real_width);
Packit 88888e
Packit 88888e
		cairo_surface_destroy (cs);
Packit 88888e
Packit 88888e
		image = gdk_pixbuf_new_from_data (pixbuf_data,
Packit 88888e
						  GDK_COLORSPACE_RGB,
Packit 88888e
						  TRUE,
Packit 88888e
						  8,
Packit 88888e
						  globals.real_width,
Packit 88888e
						  globals.current_height,
Packit 88888e
						  globals.real_width *
Packit 88888e
						  4,
Packit 88888e
						  (GdkPixbufDestroyNotify)
Packit 88888e
						  g_free, NULL);
Packit 88888e
		xkl_debug (150,
Packit 88888e
			   "Image %d created -> %p[%dx%d], alpha: %d\n",
Packit 88888e
			   group, image, gdk_pixbuf_get_width (image),
Packit 88888e
			   gdk_pixbuf_get_height (image),
Packit 88888e
			   gdk_pixbuf_get_has_alpha (image));
Packit 88888e
Packit 88888e
		return image;
Packit 88888e
	}
Packit 88888e
	return NULL;
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_update_tooltips (GkbdStatus * gki)
Packit 88888e
{
Packit 88888e
	gchar *buf =
Packit 88888e
	    gkbd_configuration_get_current_tooltip (globals.config);
Packit 88888e
	if (buf != NULL) {
Packit 88888e
		gkbd_status_set_tooltips (gki, buf);
Packit 88888e
		g_free (buf);
Packit 88888e
	}
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_reinit_globals (GkbdStatus * gki)
Packit 88888e
{
Packit 88888e
	gkbd_status_cleanup_icons ();
Packit 88888e
	gkbd_status_fill_icons (gki);
Packit 88888e
}
Packit 88888e
Packit 88888e
void
Packit 88888e
gkbd_status_reinit_ui (GkbdStatus * gki)
Packit 88888e
{
Packit 88888e
	gkbd_status_set_current_page (gki);
Packit 88888e
        /* To work around combined bugs in notification-area
Packit 88888e
         * and GtkStatusIcon, reshow the icon here, to ensure
Packit 88888e
         * size changes are picked up.
Packit 88888e
         */
Packit 88888e
        gtk_status_icon_set_visible (GTK_STATUS_ICON (gki), FALSE);
Packit 88888e
        gtk_status_icon_set_visible (GTK_STATUS_ICON (gki), TRUE);
Packit 88888e
}
Packit 88888e
Packit 88888e
/* Should be called once for all widgets */
Packit 88888e
static void
Packit 88888e
gkbd_status_cfg_callback (GkbdConfiguration * configuration)
Packit 88888e
{
Packit 88888e
	GSList *objects;
Packit 88888e
	xkl_debug (150, "Config changed: reinit ui\n");
Packit 88888e
	objects = gkbd_configuration_get_all_objects (configuration);
Packit 88888e
	if (objects)
Packit 88888e
		gkbd_status_reinit_globals (objects->data);
Packit 88888e
	ForAllObjects (configuration) {
Packit 88888e
		gkbd_status_reinit_ui (GKBD_STATUS (gki));
Packit 88888e
	} NextObject ()
Packit 88888e
}
Packit 88888e
Packit 88888e
/* Should be called once for all applets */
Packit 88888e
static void
Packit 88888e
gkbd_status_state_callback (GkbdConfiguration * configuration, gint group)
Packit 88888e
{
Packit 88888e
	xkl_debug (150, "Set page to group %d\n", group);
Packit 88888e
	ForAllObjects (configuration) {
Packit 88888e
		xkl_debug (150, "do repaint for icon %p\n", gki);
Packit 88888e
		gkbd_status_set_current_page_for_group (GKBD_STATUS (gki),
Packit 88888e
							group);
Packit 88888e
	}
Packit 88888e
	NextObject ()
Packit 88888e
}
Packit 88888e
Packit 88888e
void
Packit 88888e
gkbd_status_set_current_page (GkbdStatus * gki)
Packit 88888e
{
Packit 88888e
	XklEngine *engine =
Packit 88888e
	    gkbd_configuration_get_xkl_engine (globals.config);
Packit 88888e
	XklState *cur_state = xkl_engine_get_current_state (engine);
Packit 88888e
	if (cur_state->group >= 0)
Packit 88888e
		gkbd_status_set_current_page_for_group (gki,
Packit 88888e
							cur_state->group);
Packit 88888e
}
Packit 88888e
Packit 88888e
void
Packit 88888e
gkbd_status_set_current_page_for_group (GkbdStatus * gki, int group)
Packit 88888e
{
Packit 88888e
	GdkPixbuf *page =
Packit 88888e
	    GDK_PIXBUF (g_slist_nth_data (globals.icons, group));
Packit 88888e
	xkl_debug (150, "Revalidating for group %d: %p\n", group, page);
Packit 88888e
Packit 88888e
	if (page == NULL) {
Packit 88888e
		xkl_debug (0, "Page for group %d is not ready\n", group);
Packit 88888e
		return;
Packit 88888e
	}
Packit 88888e
Packit 88888e
	gtk_status_icon_set_from_pixbuf (GTK_STATUS_ICON (gki), page);
Packit 88888e
Packit 88888e
	gkbd_status_update_tooltips (gki);
Packit 88888e
}
Packit 88888e
Packit 88888e
/* Should be called once for all widgets */
Packit 88888e
static GdkFilterReturn
Packit 88888e
gkbd_status_filter_x_evt (GdkXEvent * xev, GdkEvent * event)
Packit 88888e
{
Packit 88888e
	XEvent *xevent = (XEvent *) xev;
Packit 88888e
	XklEngine *engine =
Packit 88888e
	    gkbd_configuration_get_xkl_engine (globals.config);
Packit 88888e
Packit 88888e
	xkl_engine_filter_events (engine, xevent);
Packit 88888e
	switch (xevent->type) {
Packit 88888e
	case ReparentNotify:
Packit 88888e
		{
Packit 88888e
			XReparentEvent *rne = (XReparentEvent *) xev;
Packit 88888e
Packit 88888e
			ForAllObjects (globals.config) {
Packit 88888e
				guint32 xid =
Packit 88888e
				    gtk_status_icon_get_x11_window_id
Packit 88888e
				    (GTK_STATUS_ICON (gki));
Packit 88888e
Packit 88888e
				/* compare the indicator's parent window with the even window */
Packit 88888e
				if (xid == rne->window) {
Packit 88888e
					/* if so - make it transparent... */
Packit 88888e
					xkl_engine_set_window_transparent
Packit 88888e
					    (engine, rne->window, TRUE);
Packit 88888e
				}
Packit 88888e
			}
Packit 88888e
		NextObject ()}
Packit 88888e
		break;
Packit 88888e
	}
Packit 88888e
	return GDK_FILTER_CONTINUE;
Packit 88888e
}
Packit 88888e
Packit 88888e
Packit 88888e
/* Should be called once for all widgets */
Packit 88888e
static void
Packit 88888e
gkbd_status_start_listen (void)
Packit 88888e
{
Packit 88888e
	gdk_window_add_filter (NULL, (GdkFilterFunc)
Packit 88888e
			       gkbd_status_filter_x_evt, NULL);
Packit 88888e
	gdk_window_add_filter (gdk_get_default_root_window (),
Packit 88888e
			       (GdkFilterFunc) gkbd_status_filter_x_evt,
Packit 88888e
			       NULL);
Packit 88888e
}
Packit 88888e
Packit 88888e
/* Should be called once for all widgets */
Packit 88888e
static void
Packit 88888e
gkbd_status_stop_listen (void)
Packit 88888e
{
Packit 88888e
	gdk_window_remove_filter (NULL, (GdkFilterFunc)
Packit 88888e
				  gkbd_status_filter_x_evt, NULL);
Packit 88888e
	gdk_window_remove_filter
Packit 88888e
	    (gdk_get_default_root_window (),
Packit 88888e
	     (GdkFilterFunc) gkbd_status_filter_x_evt, NULL);
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_size_changed (GkbdStatus * gki, gint size)
Packit 88888e
{
Packit 88888e
	xkl_debug (150, "Size changed to %d\n", size);
Packit 88888e
        /* Ignore the initial size 200 that we get before
Packit 88888e
         * we are embedded
Packit 88888e
         */
Packit 88888e
        if (!gtk_status_icon_is_embedded (GTK_STATUS_ICON (gki)))
Packit 88888e
                return;
Packit 88888e
	if (globals.current_height != size) {
Packit 88888e
		globals.current_height = size;
Packit 88888e
		globals.current_width = size * 3 / 2;
Packit 88888e
		gkbd_status_reinit_globals (gki);
Packit 88888e
		gkbd_status_reinit_ui (gki);
Packit 88888e
	}
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_theme_changed (GtkSettings * settings, GParamSpec * pspec,
Packit 88888e
			   GkbdStatus * gki)
Packit 88888e
{
Packit 88888e
	xkl_debug (150, "Theme changed\n");
Packit 88888e
	gkbd_indicator_config_refresh_style
Packit 88888e
	    (gkbd_configuration_get_indicator_config (globals.config));
Packit 88888e
	gkbd_status_reinit_globals (gki);
Packit 88888e
	gkbd_status_reinit_ui (gki);
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_init (GkbdStatus * gki)
Packit 88888e
{
Packit 88888e
	int i;
Packit 88888e
Packit 88888e
	if (!gkbd_configuration_if_any_object_exists (globals.config))
Packit 88888e
		gkbd_status_global_init ();
Packit 88888e
Packit 88888e
	gki->priv = g_new0 (GkbdStatusPrivate, 1);
Packit 88888e
Packit 88888e
	/* This should give Notification Area a hint about the order of icons */
Packit 88888e
	gtk_status_icon_set_name (GTK_STATUS_ICON (gki), "keyboard");
Packit 88888e
Packit 88888e
	xkl_debug (100, "The status icon startup process for %p started\n",
Packit 88888e
		   gki);
Packit 88888e
Packit 88888e
	if (gkbd_configuration_get_xkl_engine (globals.config) == NULL) {
Packit 88888e
		gkbd_status_set_tooltips (gki,
Packit 88888e
					  _("XKB initialization error"));
Packit 88888e
		return;
Packit 88888e
	}
Packit 88888e
Packit 88888e
	/* append AFTER all initialization work is finished */
Packit 88888e
	gkbd_configuration_append_object (globals.config, G_OBJECT (gki));
Packit 88888e
Packit 88888e
	g_signal_connect (gki, "size-changed",
Packit 88888e
			  G_CALLBACK (gkbd_status_size_changed), NULL);
Packit 88888e
	g_signal_connect (gki, "activate",
Packit 88888e
			  G_CALLBACK (gkbd_status_activate), NULL);
Packit 88888e
Packit 88888e
	for (i = sizeof (settings_signal_names) /
Packit 88888e
	     sizeof (settings_signal_names[0]); --i >= 0;)
Packit 88888e
		gki->priv->settings_signal_handlers[i] =
Packit 88888e
		    g_signal_connect_after (gtk_settings_get_default (),
Packit 88888e
					    settings_signal_names[i],
Packit 88888e
					    G_CALLBACK
Packit 88888e
					    (gkbd_status_theme_changed),
Packit 88888e
					    gki);
Packit 88888e
Packit 88888e
	xkl_debug (100,
Packit 88888e
		   "The status icon startup process for %p completed\n",
Packit 88888e
		   gki);
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_finalize (GObject * obj)
Packit 88888e
{
Packit 88888e
	int i;
Packit 88888e
	GkbdStatus *gki = GKBD_STATUS (obj);
Packit 88888e
	xkl_debug (100,
Packit 88888e
		   "Starting the gnome-kbd-status widget shutdown process for %p\n",
Packit 88888e
		   gki);
Packit 88888e
Packit 88888e
	for (i = sizeof (settings_signal_names) /
Packit 88888e
	     sizeof (settings_signal_names[0]); --i >= 0;)
Packit 88888e
		g_signal_handler_disconnect (gtk_settings_get_default (),
Packit 88888e
					     gki->
Packit 88888e
					     priv->settings_signal_handlers
Packit 88888e
					     [i]);
Packit 88888e
Packit 88888e
	/* remove BEFORE all termination work is finished */
Packit 88888e
	gkbd_configuration_remove_object (globals.config, G_OBJECT (gki));
Packit 88888e
Packit 88888e
	gkbd_status_cleanup_icons ();
Packit 88888e
Packit 88888e
	xkl_debug (100,
Packit 88888e
		   "The instance of gnome-kbd-status successfully finalized\n");
Packit 88888e
Packit 88888e
	g_free (gki->priv);
Packit 88888e
Packit 88888e
	G_OBJECT_CLASS (gkbd_status_parent_class)->finalize (obj);
Packit 88888e
Packit 88888e
	if (!gkbd_configuration_if_any_object_exists (globals.config))
Packit 88888e
		gkbd_status_global_term ();
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_global_term (void)
Packit 88888e
{
Packit 88888e
	xkl_debug (100, "*** Last  GkbdStatus instance *** \n");
Packit 88888e
	gkbd_status_stop_listen ();
Packit 88888e
Packit 88888e
	g_object_unref (globals.config);
Packit 88888e
	globals.config = NULL;
Packit 88888e
Packit 88888e
	xkl_debug (100, "*** Terminated globals *** \n");
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_class_init (GkbdStatusClass * klass)
Packit 88888e
{
Packit 88888e
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit 88888e
Packit 88888e
	xkl_debug (100, "*** First GkbdStatus instance *** \n");
Packit 88888e
Packit 88888e
	memset (&globals, 0, sizeof (globals));
Packit 88888e
Packit 88888e
	/* Initing vtable */
Packit 88888e
	object_class->finalize = gkbd_status_finalize;
Packit 88888e
}
Packit 88888e
Packit 88888e
static void
Packit 88888e
gkbd_status_global_init (void)
Packit 88888e
{
Packit 88888e
	globals.config = gkbd_configuration_get ();
Packit 88888e
Packit 88888e
	g_signal_connect (globals.config, "group-changed",
Packit 88888e
			  G_CALLBACK (gkbd_status_state_callback), NULL);
Packit 88888e
	g_signal_connect (globals.config, "changed",
Packit 88888e
			  G_CALLBACK (gkbd_status_cfg_callback), NULL);
Packit 88888e
Packit 88888e
	gkbd_status_start_listen ();
Packit 88888e
Packit 88888e
	xkl_debug (100, "*** Inited globals *** \n");
Packit 88888e
}
Packit 88888e
Packit 88888e
GtkStatusIcon *
Packit 88888e
gkbd_status_new (void)
Packit 88888e
{
Packit 88888e
	return
Packit 88888e
	    GTK_STATUS_ICON (g_object_new (gkbd_status_get_type (), NULL));
Packit 88888e
}
Packit 88888e
Packit 88888e
/**
Packit 88888e
 * gkbd_status_get_xkl_engine:
Packit 88888e
 *
Packit 88888e
 * Returns: (transfer none): The engine shared by all GkbdStatus objects
Packit 88888e
 */
Packit 88888e
XklEngine *
Packit 88888e
gkbd_status_get_xkl_engine ()
Packit 88888e
{
Packit 88888e
	return gkbd_configuration_get_xkl_engine (globals.config);
Packit 88888e
}
Packit 88888e
Packit 88888e
/**
Packit 88888e
 * gkbd_status_get_group_names:
Packit 88888e
 *
Packit 88888e
 * Returns: (transfer none) (array zero-terminated=1): List of group names
Packit 88888e
 */
Packit 88888e
gchar **
Packit 88888e
gkbd_status_get_group_names ()
Packit 88888e
{
Packit 88888e
	return (gchar **)
Packit 88888e
	    gkbd_configuration_get_group_names (globals.config);
Packit 88888e
}
Packit 88888e
Packit 88888e
gchar *
Packit 88888e
gkbd_status_get_image_filename (guint group)
Packit 88888e
{
Packit 88888e
	return gkbd_configuration_get_image_filename (globals.config,
Packit 88888e
						      group);
Packit 88888e
}