gtk+ r21547 - in trunk: . gtk
- From: matthiasc svn gnome org
- To: svn-commits-list gnome org
- Subject: gtk+ r21547 - in trunk: . gtk
- Date: Mon, 29 Sep 2008 21:57:29 +0000 (UTC)
Author: matthiasc
Date: Mon Sep 29 21:57:29 2008
New Revision: 21547
URL: http://svn.gnome.org/viewvc/gtk+?rev=21547&view=rev
Log:
2008-09-29 Matthias Clasen <mclasen redhat com>
Bug 530568 â Entries with visibility=FALSE should warn for caps-lock
on
* gtk/gtkentry.c: Add a tooltip-like Caps Lock warning for
password entries. The warning is also triggered if an input method
is active. The warning can be turned off using the
GtkEntry::caps-lock-warning property.
Proposed by Owen Taylor
Modified:
trunk/ChangeLog
trunk/gtk/gtkentry.c
Modified: trunk/gtk/gtkentry.c
==============================================================================
--- trunk/gtk/gtkentry.c (original)
+++ trunk/gtk/gtkentry.c Mon Sep 29 21:57:29 2008
@@ -31,6 +31,7 @@
#include <pango/pango.h>
#include "gdk/gdkkeysyms.h"
+#include "gtkalignment.h"
#include "gtkbindings.h"
#include "gtkcelleditable.h"
#include "gtkclipboard.h"
@@ -40,6 +41,7 @@
#include "gtkimcontextsimple.h"
#include "gtkimmulticontext.h"
#include "gtkintl.h"
+#include "gtklabel.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkmenu.h"
@@ -75,6 +77,7 @@
static GQuark quark_inner_border = 0;
static GQuark quark_password_hint = 0;
static GQuark quark_cursor_hadjustment = 0;
+static GQuark quark_capslock_feedback = 0;
typedef struct _GtkEntryPrivate GtkEntryPrivate;
@@ -88,6 +91,7 @@
guint interior_focus : 1;
guint real_changed : 1;
guint invisible_char_set : 1;
+ guint caps_lock_warning : 1;
guint change_count : 8;
gint focus_width;
@@ -104,6 +108,15 @@
gint password_hint_position;
};
+typedef struct _GtkEntryCapslockFeedback GtkEntryCapslockFeedback;
+
+struct _GtkEntryCapslockFeedback
+{
+ GtkWidget *entry;
+ GtkWidget *window;
+ GtkWidget *label;
+};
+
enum {
ACTIVATE,
POPULATE_POPUP,
@@ -137,7 +150,8 @@
PROP_SHADOW_TYPE,
PROP_OVERWRITE_MODE,
PROP_TEXT_LENGTH,
- PROP_INVISIBLE_CHAR_SET
+ PROP_INVISIBLE_CHAR_SET,
+ PROP_CAPS_LOCK_WARNING
};
static guint signals[LAST_SIGNAL] = { 0 };
@@ -278,10 +292,14 @@
static void gtk_entry_toggle_overwrite (GtkEntry *entry);
static void gtk_entry_select_all (GtkEntry *entry);
static void gtk_entry_real_activate (GtkEntry *entry);
-static gboolean gtk_entry_popup_menu (GtkWidget *widget);
+static gboolean gtk_entry_popup_menu (GtkWidget *widget);
+
+static void keymap_direction_changed (GdkKeymap *keymap,
+ GtkEntry *entry);
+static void keymap_state_changed (GdkKeymap *keymap,
+ GtkEntry *entry);
+static void remove_capslock_feedback (GtkEntry *entry);
-static void gtk_entry_keymap_direction_changed (GdkKeymap *keymap,
- GtkEntry *entry);
/* IM Context Callbacks
*/
static void gtk_entry_commit_cb (GtkIMContext *context,
@@ -393,6 +411,7 @@
static void end_change (GtkEntry *entry);
static void emit_changed (GtkEntry *entry);
+
G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
gtk_entry_editable_init)
@@ -481,6 +500,7 @@
quark_inner_border = g_quark_from_static_string ("gtk-entry-inner-border");
quark_password_hint = g_quark_from_static_string ("gtk-entry-password-hint");
quark_cursor_hadjustment = g_quark_from_static_string ("gtk-hadjustment");
+ quark_capslock_feedback = g_quark_from_static_string ("gtk-entry-capslock-feedback");
g_object_class_install_property (gobject_class,
PROP_CURSOR_POSITION,
@@ -681,6 +701,25 @@
FALSE,
GTK_PARAM_READWRITE));
+
+
+ /**
+ * GtkEntry:caps-lock-warning
+ *
+ * Whether password entries will show a warning when Caps Lock is on
+ * or an input method is active.
+ *
+ * Since: 2.16
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_CAPS_LOCK_WARNING,
+ g_param_spec_boolean ("caps-lock-warning",
+ P_("Caps Lock warning"),
+ P_("Whether password entries will show a warning when Caps Lock is on or an input method is active"),
+ TRUE,
+ GTK_PARAM_READWRITE));
+
+
signals[POPULATE_POPUP] =
g_signal_new (I_("populate-popup"),
G_OBJECT_CLASS_TYPE (gobject_class),
@@ -1085,6 +1124,11 @@
else
gtk_entry_unset_invisible_char (entry);
break;
+
+ case PROP_CAPS_LOCK_WARNING:
+ priv->caps_lock_warning = g_value_get_boolean (value);
+ break;
+
case PROP_SCROLL_OFFSET:
case PROP_CURSOR_POSITION:
default:
@@ -1158,6 +1202,9 @@
case PROP_INVISIBLE_CHAR_SET:
g_value_set_boolean (value, priv->invisible_char_set);
break;
+ case PROP_CAPS_LOCK_WARNING:
+ g_value_set_boolean (value, priv->caps_lock_warning);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1228,6 +1275,7 @@
entry->truncate_multiline = FALSE;
priv->shadow_type = GTK_SHADOW_IN;
priv->xalign = 0.0;
+ priv->caps_lock_warning = TRUE;
gtk_drag_dest_set (GTK_WIDGET (entry),
GTK_DEST_DEFAULT_HIGHLIGHT,
@@ -2238,18 +2286,23 @@
GdkEventFocus *event)
{
GtkEntry *entry = GTK_ENTRY (widget);
-
+ GdkKeymap *keymap;
+
gtk_widget_queue_draw (widget);
-
+
+ keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
+
if (entry->editable)
{
entry->need_im_reset = TRUE;
gtk_im_context_focus_in (entry->im_context);
+ keymap_state_changed (keymap, entry);
+ g_signal_connect (keymap, "state-changed",
+ G_CALLBACK (keymap_state_changed), entry);
}
- g_signal_connect (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
- "direction-changed",
- G_CALLBACK (gtk_entry_keymap_direction_changed), entry);
+ g_signal_connect (keymap, "direction-changed",
+ G_CALLBACK (keymap_direction_changed), entry);
gtk_entry_reset_blink_time (entry);
gtk_entry_check_cursor_blink (entry);
@@ -2263,20 +2316,23 @@
{
GtkEntry *entry = GTK_ENTRY (widget);
GtkEntryCompletion *completion;
+ GdkKeymap *keymap;
gtk_widget_queue_draw (widget);
+ keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
+
if (entry->editable)
{
entry->need_im_reset = TRUE;
gtk_im_context_focus_out (entry->im_context);
+ remove_capslock_feedback (entry);
}
gtk_entry_check_cursor_blink (entry);
- g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
- gtk_entry_keymap_direction_changed,
- entry);
+ g_signal_handlers_disconnect_by_func (keymap, keymap_state_changed, entry);
+ g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, entry);
completion = gtk_entry_get_completion (entry);
if (completion)
@@ -3160,8 +3216,8 @@
}
static void
-gtk_entry_keymap_direction_changed (GdkKeymap *keymap,
- GtkEntry *entry)
+keymap_direction_changed (GdkKeymap *keymap,
+ GtkEntry *entry)
{
gtk_entry_recompute (entry);
}
@@ -3429,7 +3485,6 @@
else
{
gint ch_len;
- gint preedit_len_chars;
gunichar invisible_char;
if (entry->invisible_char != 0)
@@ -5450,9 +5505,6 @@
"gtk-show-unicode-menu", &show_unicode_menu,
NULL);
- if (!entry->visible)
- show_input_method_menu = FALSE;
-
if (show_input_method_menu || show_unicode_menu)
{
menuitem = gtk_separator_menu_item_new ();
@@ -6536,5 +6588,171 @@
return g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment);
}
+/* Caps Lock warning for password entries */
+
+static void
+capslock_feedback_free (GtkEntryCapslockFeedback *feedback)
+{
+ if (feedback->window)
+ gtk_widget_destroy (feedback->window);
+
+ g_slice_free (GtkEntryCapslockFeedback, feedback);
+}
+
+static gboolean
+capslock_feedback_expose_event_cb (GtkWidget *widget,
+ GdkEventExpose *event,
+ GtkEntryCapslockFeedback *feedback)
+{
+ gtk_paint_flat_box (feedback->window->style,
+ feedback->window->window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ NULL,
+ feedback->window,
+ "tooltip",
+ 0, 0,
+ feedback->window->allocation.width,
+ feedback->window->allocation.height);
+ return FALSE;
+}
+
+static gboolean
+capslock_feedback_enter_notify (GtkWidget *widget,
+ GdkEventCrossing *event,
+ GtkEntryCapslockFeedback *feedback)
+{
+ remove_capslock_feedback (GTK_ENTRY (feedback->entry));
+ return TRUE;
+}
+
+static void
+create_capslock_feedback_window (GtkEntryCapslockFeedback *feedback)
+{
+ GtkWidget *window;
+ GtkWidget *alignment;
+ GtkWidget *label;
+
+ /* Keep in sync with gtk_tooltip_init() */
+ window = feedback->window = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_TOOLTIP);
+ gtk_widget_set_app_paintable (window, TRUE);
+ gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+ gtk_widget_set_name (window, "gtk-tooltip");
+
+ alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
+ window->style->ythickness,
+ window->style->ythickness,
+ window->style->xthickness,
+ window->style->xthickness);
+ gtk_container_add (GTK_CONTAINER (window), alignment);
+ gtk_widget_show (alignment);
+
+ g_signal_connect (window, "expose-event",
+ G_CALLBACK (capslock_feedback_expose_event_cb), feedback);
+ g_signal_connect (window, "enter-notify-event",
+ G_CALLBACK (capslock_feedback_enter_notify), feedback);
+
+ label = feedback->label = gtk_label_new (NULL);
+ gtk_container_add (GTK_CONTAINER (alignment), label);
+ gtk_widget_show (label);
+}
+
+static void
+show_capslock_feedback_window (GtkEntryCapslockFeedback *feedback)
+{
+ GtkRequisition feedback_req;
+ gint entry_x, entry_y;
+ GtkAllocation *entry_allocation;
+ int feedback_x, feedback_y;
+ GdkScreen *screen;
+ gint monitor_num;
+ GdkRectangle monitor;
+ GtkWidget *entry;
+
+ entry = feedback->entry;
+ screen = gtk_widget_get_screen (entry);
+ monitor_num = gdk_screen_get_monitor_at_window (screen, entry->window);
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+ feedback = g_object_get_qdata (G_OBJECT (entry), quark_capslock_feedback);
+
+ gtk_widget_size_request (feedback->window, &feedback_req);
+
+ gdk_window_get_origin (entry->window, &entry_x, &entry_y);
+ entry_allocation = &(entry->allocation);
+
+ if (entry_x + feedback_req.width <= monitor.x + monitor.width)
+ feedback_x = MAX (entry_x, monitor.x);
+ else
+ feedback_x = monitor.x + monitor.width - feedback_req.width;
+
+ if (entry_y + entry_allocation->height + feedback_req.height <= monitor.y + monitor.height)
+ feedback_y = entry_y + entry_allocation->height;
+ else
+ feedback_y = MAX (entry_y - feedback_req.height, monitor.y);
+
+ gtk_window_move (GTK_WINDOW (feedback->window), feedback_x, feedback_y);
+ gtk_widget_show (feedback->window);
+}
+
+static void
+pop_up_capslock_feedback (GtkEntry *entry,
+ const gchar *text)
+{
+ GtkEntryCapslockFeedback *feedback;
+
+ feedback = g_object_get_qdata (G_OBJECT (entry), quark_capslock_feedback);
+
+ if (feedback == NULL)
+ {
+ feedback = g_slice_new0 (GtkEntryCapslockFeedback);
+ feedback->entry = entry;
+ g_object_set_qdata_full (G_OBJECT (entry), quark_capslock_feedback,
+ feedback,
+ (GDestroyNotify) capslock_feedback_free);
+ create_capslock_feedback_window (feedback);
+ }
+
+ gtk_label_set_text (GTK_LABEL (feedback->label), text);
+ show_capslock_feedback_window (feedback);
+}
+
+static void
+remove_capslock_feedback (GtkEntry *entry)
+{
+ g_object_set_qdata (G_OBJECT (entry), quark_capslock_feedback, NULL);
+}
+
+static void
+keymap_state_changed (GdkKeymap *keymap,
+ GtkEntry *entry)
+{
+ GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
+ char *text = NULL;
+
+ if (!entry->visible && priv->caps_lock_warning)
+ {
+ gboolean capslock_on;
+ gboolean im_on;
+
+ capslock_on = gdk_keymap_get_caps_lock_state (keymap);
+ im_on = g_strcmp0 (gtk_im_multicontext_get_context_id (GTK_IM_MULTICONTEXT (entry->im_context)), "gtk-im-context-simple") != 0;
+ if (capslock_on && im_on)
+ text = _("You have the Caps Lock key on\nand an active input method");
+ else if (capslock_on)
+ text = _("You have the Caps Lock key on");
+ else if (im_on)
+ text = _("You have an active input method");
+ }
+
+ if (text)
+ pop_up_capslock_feedback (entry, text);
+ else
+ remove_capslock_feedback (entry);
+}
+
+
#define __GTK_ENTRY_C__
#include "gtkaliasdef.c"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]