]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkentrycompletion.c
Don't call gtk_tree_view_scroll_to_cell() on an empty tree view. It
[~andy/gtk] / gtk / gtkentrycompletion.c
index c1ee65a588287f0cfcfbd283b4f1c83ffac176ae..680ab815b123633921113b3ae47f635c36889058 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+#include <config.h>
 #include "gtkentrycompletion.h"
 #include "gtkentryprivate.h"
 #include "gtkcelllayout.h"
 
 #include "gtkintl.h"
 #include "gtkcellrenderertext.h"
+#include "gtkframe.h"
 #include "gtktreeselection.h"
 #include "gtktreeview.h"
 #include "gtkscrolledwindow.h"
@@ -173,6 +175,19 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass)
   object_class->get_property = gtk_entry_completion_get_property;
   object_class->finalize = gtk_entry_completion_finalize;
 
+  /**
+   * GtkEntryCompletion::match-selected:
+   * @widget: the object which received the signal
+   * @model: the #GtkTreeModel containing the matches
+   * @iter: a #GtkTreeIter positioned at the selected match
+   * 
+   * The ::match-selected signal is emitted when a match from the list
+   * is selected. The default behaviour is to replace the contents of the
+   * entry with the contents of the text column in the row pointed to by
+   * @iter.
+   *
+   * Return value: %TRUE if the signal has been handled
+   */ 
   entry_completion_signals[MATCH_SELECTED] =
     g_signal_new ("match_selected",
                   G_TYPE_FROM_CLASS (klass),
@@ -183,6 +198,15 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass)
                   G_TYPE_BOOLEAN, 2,
                   GTK_TYPE_TREE_MODEL,
                   GTK_TYPE_TREE_ITER);
+                 
+  /**
+   * GtkEntryCompletion::action-activated:
+   * @widget: the object which received the signal
+   * @index: the index of the activated action
+   *
+   * The ::action-activated signal is emitted when an action
+   * is activated.
+   */
   entry_completion_signals[ACTION_ACTIVATED] =
     g_signal_new ("action_activated",
                   G_TYPE_FROM_CLASS (klass),
@@ -231,6 +255,7 @@ gtk_entry_completion_init (GtkEntryCompletion *completion)
   GtkCellRenderer *cell;
   GtkTreeSelection *sel;
   GtkEntryCompletionPrivate *priv;
+  GtkWidget *popup_frame;
 
   /* yes, also priv, need to keep the code readable */
   priv = completion->priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (completion);
@@ -263,7 +288,7 @@ gtk_entry_completion_init (GtkEntryCompletion *completion)
                                   GTK_POLICY_NEVER,
                                   GTK_POLICY_AUTOMATIC);
   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scrolled_window),
-                                       GTK_SHADOW_ETCHED_IN);
+                                       GTK_SHADOW_NONE);
 
   /* a nasty hack to get the completions treeview to size nicely */
   gtk_widget_set_size_request (GTK_SCROLLED_WINDOW (priv->scrolled_window)->vscrollbar, -1, 0);
@@ -283,9 +308,6 @@ gtk_entry_completion_init (GtkEntryCompletion *completion)
   gtk_tree_selection_unselect_all (sel);
 
   cell = gtk_cell_renderer_text_new ();
-  g_object_set (cell, "cell_background_gdk",
-                &priv->tree_view->style->bg[GTK_STATE_NORMAL],
-                NULL);
   gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (priv->action_view),
                                               0, "",
                                               cell,
@@ -303,8 +325,14 @@ gtk_entry_completion_init (GtkEntryCompletion *completion)
                     G_CALLBACK (gtk_entry_completion_popup_button_press),
                     completion);
 
+  popup_frame = gtk_frame_new (NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (popup_frame),
+                            GTK_SHADOW_ETCHED_IN);
+  gtk_widget_show (popup_frame);
+  gtk_container_add (GTK_CONTAINER (priv->popup_window), popup_frame);
+  
   priv->vbox = gtk_vbox_new (FALSE, 0);
-  gtk_container_add (GTK_CONTAINER (priv->popup_window), priv->vbox);
+  gtk_container_add (GTK_CONTAINER (popup_frame), priv->vbox);
 
   gtk_container_add (GTK_CONTAINER (priv->scrolled_window), priv->tree_view);
   gtk_box_pack_start (GTK_BOX (priv->vbox), priv->scrolled_window,
@@ -539,17 +567,16 @@ gtk_entry_completion_visible_func (GtkTreeModel *model,
   if (!completion->priv->case_normalized_key)
     return ret;
 
-  if (completion->priv->text_column >= 0)
-    ret = gtk_entry_completion_default_completion_func (completion,
-                                                        completion->priv->case_normalized_key,
-                                                        iter,
-                                                        NULL);
-
-  else if (completion->priv->match_func)
+  if (completion->priv->match_func)
     ret = (* completion->priv->match_func) (completion,
                                             completion->priv->case_normalized_key,
                                             iter,
                                             completion->priv->match_data);
+  else if (completion->priv->text_column >= 0)
+    ret = gtk_entry_completion_default_completion_func (completion,
+                                                        completion->priv->case_normalized_key,
+                                                        iter,
+                                                        NULL);
 
   return ret;
 }
@@ -608,9 +635,13 @@ gtk_entry_completion_list_button_press (GtkWidget      *widget,
                                &iter, path);
       gtk_tree_path_free (path);
 
+      g_signal_handler_block (completion->priv->entry,
+                             completion->priv->changed_id);
       g_signal_emit (completion, entry_completion_signals[MATCH_SELECTED],
                      0, GTK_TREE_MODEL (completion->priv->filter_model),
                      &iter, &entry_set);
+      g_signal_handler_unblock (completion->priv->entry,
+                               completion->priv->changed_id);
 
       if (!entry_set)
         {
@@ -999,11 +1030,13 @@ gtk_entry_completion_delete_action (GtkEntryCompletion *completion,
  * @completion: A #GtkEntryCompletion.
  * @column: The column in the model of @completion to get strings from.
  *
- * Convience function for setting up the most used case of this code: a
+ * Convenience function for setting up the most used case of this code: a
  * completion list with just strings. This function will set up @completion
  * to have a list displaying all (and just) strings in the completion list,
  * and to get those strings from @column in the model of @completion.
  *
+ * This functions creates and adds a GtkCellRendererText for the selected column.
+
  * Since: 2.4
  */
 void
@@ -1061,16 +1094,27 @@ get_borders (GtkEntry *entry,
 }
 
 /* some nasty size requisition */
-gint
+gboolean
 _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion)
 {
-  gint items, height, x_border, y_border;
+  gint x, y;
+  gint matches, items, height, x_border, y_border;
+  GdkScreen *screen;
+  gint monitor_num;
+  GdkRectangle monitor;
+  GtkRequisition popup_req;
+  GtkTreePath *path;
+  gboolean above;
 
+  gdk_window_get_origin (completion->priv->entry->window, &x, &y);
   get_borders (GTK_ENTRY (completion->priv->entry), &x_border, &y_border);
 
-  items = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
+  x += x_border;
+  y += 2 * y_border;
 
-  items = MIN (items, 15);
+  matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
+
+  items = MIN (matches, 15);
 
   gtk_tree_view_column_cell_get_size (completion->priv->column, NULL,
                                       NULL, NULL, NULL, &height);
@@ -1104,29 +1148,64 @@ _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion)
   else
     gtk_widget_hide (completion->priv->action_view);
 
-  return height;
+  gtk_widget_size_request (completion->priv->popup_window, &popup_req);
+
+  screen = gtk_widget_get_screen (GTK_WIDGET (completion->priv->entry));
+  monitor_num = gdk_screen_get_monitor_at_window (screen, 
+                                                 GTK_WIDGET (completion->priv->entry)->window);
+  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+  
+  if (x < monitor.x)
+    x = monitor.x;
+  else if (x + popup_req.width > monitor.x + monitor.width)
+    x = monitor.x + monitor.width - popup_req.width;
+  
+  if (y + height + popup_req.height <= monitor.y + monitor.height)
+    {
+      y += height;
+      above = FALSE;
+    }
+  else
+    {
+      y -= popup_req.height;
+      above = TRUE;
+    }
+  
+  if (matches > 0) 
+    {
+      path = gtk_tree_path_new_from_indices (above ? matches - 1 : 0, -1);
+      gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (completion->priv->tree_view), path, 
+                                   NULL, FALSE, 0.0, 0.0);
+      gtk_tree_path_free (path);
+    }
+
+  gtk_window_move (GTK_WINDOW (completion->priv->popup_window), x, y);
+
+  return above;
 }
 
 void
 _gtk_entry_completion_popup (GtkEntryCompletion *completion)
 {
-  gint x, y, x_border, y_border;
-  gint height;
+  GtkTreeViewColumn *column;
+  GList *renderers;
 
   if (GTK_WIDGET_MAPPED (completion->priv->popup_window))
     return;
 
-  gtk_widget_show_all (completion->priv->vbox);
-
-  gdk_window_get_origin (completion->priv->entry->window, &x, &y);
-  get_borders (GTK_ENTRY (completion->priv->entry), &x_border, &y_border);
+  completion->priv->may_wrap = TRUE;
 
-  x += x_border;
-  y += 2 * y_border;
+  column = gtk_tree_view_get_column (GTK_TREE_VIEW (completion->priv->action_view), 0);
+  renderers = gtk_tree_view_column_get_cell_renderers (column);
+  gtk_widget_ensure_style (completion->priv->tree_view);
+  g_object_set (GTK_CELL_RENDERER (renderers->data), "cell_background_gdk",
+                &completion->priv->tree_view->style->bg[GTK_STATE_NORMAL],
+                NULL);
+  g_list_free (renderers);
 
-  height = _gtk_entry_completion_resize_popup (completion);
+  gtk_widget_show_all (completion->priv->vbox);
 
-  gtk_window_move (GTK_WINDOW (completion->priv->popup_window), x, y + height);
+  _gtk_entry_completion_resize_popup (completion);
 
   gtk_widget_show (completion->priv->popup_window);