Ticket #4381: 0001-OSK-im-osk-position_v8.patch

File 0001-OSK-im-osk-position_v8.patch, 24.0 KB (added by erikos, 10 years ago)

new GTK3-OSK patch that fixes a lock up

  • gtk/gtkimcontext.c

    From bd18b70db320985520adb418cc5ffc8e9cb20f36 Mon Sep 17 00:00:00 2001
    From: Carlos Garnacho <carlos@lanedo.com>
    Date: Wed, 19 Sep 2012 15:37:01 +0200
    Subject: [PATCH] OSK: im-osk-position
    
    Patch based on: http://git.gnome.org/browse/gtk+/log/?h=wip/im-osk-position
    ---
     gtk/gtkimcontext.c      | 181 +++++++++++++++++++++++++++++++++++++++++++++++-
     gtk/gtkimmulticontext.c |  20 ++++++
     gtk/gtkscrolledwindow.c | 132 +++++++++++++++++++++++++++++++----
     gtk/gtkwidget.c         |  66 ++++++++++++++++++
     gtk/gtkwidget.h         |   6 ++
     5 files changed, 390 insertions(+), 15 deletions(-)
    
    diff --git a/gtk/gtkimcontext.c b/gtk/gtkimcontext.c
    index f0f351f..7b84e05 100644
    a b enum { 
    105105  COMMIT,
    106106  RETRIEVE_SURROUNDING,
    107107  DELETE_SURROUNDING,
     108  CLEAR_AREA,
    108109  LAST_SIGNAL
    109110};
    110111
    typedef struct _GtkIMContextPrivate GtkIMContextPrivate; 
    121122struct _GtkIMContextPrivate {
    122123  GtkInputPurpose purpose;
    123124  GtkInputHints hints;
     125  GdkWindow *window;
     126  GtkWidget *widget;
     127
     128  cairo_rectangle_int_t clear_area;
     129  cairo_rectangle_int_t cursor_rect;
     130  cairo_rectangle_int_t last_notified_clear_area;
     131  guint clear_area_signal_id;
     132  guint clear_area_idle_id;
     133  guint focused : 1;
     134  guint need_unset : 1;
     135  guint need_position_update : 1;
    124136};
    125137
    126138static void     gtk_im_context_real_get_preedit_string (GtkIMContext   *context,
    static void gtk_im_context_set_property (GObject *obj, 
    145157                                                        guint           property_id,
    146158                                                        const GValue   *value,
    147159                                                        GParamSpec     *pspec);
     160static void     gtk_im_context_finalize                (GObject        *obj);
    148161
    149162
    150163G_DEFINE_ABSTRACT_TYPE (GtkIMContext, gtk_im_context, G_TYPE_OBJECT)
    gtk_im_context_class_init (GtkIMContextClass *klass) 
    213226
    214227  object_class->get_property = gtk_im_context_get_property;
    215228  object_class->set_property = gtk_im_context_set_property;
     229  object_class->finalize = gtk_im_context_finalize;
    216230
    217231  klass->get_preedit_string = gtk_im_context_real_get_preedit_string;
    218232  klass->filter_keypress = gtk_im_context_real_filter_keypress;
    gtk_im_context_class_init (GtkIMContextClass *klass) 
    327341                  G_TYPE_INT,
    328342                  G_TYPE_INT);
    329343
     344  im_context_signals[CLEAR_AREA] =
     345      g_signal_new (I_("clear-area"),
     346                    G_TYPE_FROM_CLASS (klass),
     347                    G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
     348                    0, NULL, NULL,
     349                    _gtk_marshal_VOID__BOXED_BOXED,
     350                    G_TYPE_NONE, 2,
     351                    GDK_TYPE_RECTANGLE, GDK_TYPE_RECTANGLE);
     352
    330353  properties[PROP_INPUT_PURPOSE] =
    331354    g_param_spec_enum ("input-purpose",
    332355                         P_("Purpose"),
    gtk_im_context_real_get_surrounding (GtkIMContext *context, 
    438461  return result;
    439462}
    440463
     464static gboolean
     465_gtk_im_context_clear_area_idle (gpointer user_data)
     466{
     467  GtkIMContext *context = user_data;
     468  GtkIMContextPrivate *priv;
     469
     470  priv = G_TYPE_INSTANCE_GET_PRIVATE (context, GTK_TYPE_IM_CONTEXT,
     471                                      GtkIMContextPrivate);
     472
     473  if (priv->need_position_update &&
     474      (priv->clear_area.x != priv->last_notified_clear_area.x ||
     475       priv->clear_area.y != priv->last_notified_clear_area.y ||
     476       priv->clear_area.width != priv->last_notified_clear_area.width ||
     477       priv->clear_area.height != priv->last_notified_clear_area.height))
     478    {
     479      if (priv->focused &&
     480          priv->clear_area.width != 0 && priv->clear_area.height != 0)
     481        {
     482          cairo_rectangle_int_t rect;
     483          GtkAllocation allocation;
     484
     485          rect = priv->cursor_rect;
     486          gdk_window_get_root_coords (priv->window,
     487                                      rect.x, rect.y, &rect.x, &rect.y);
     488
     489          if (gtk_widget_request_clear_area (priv->widget, &priv->clear_area, &rect))
     490            priv->need_unset = TRUE;
     491        }
     492      else if (!priv->focused && priv->need_unset)
     493        {
     494          gtk_widget_unset_clear_area (priv->widget, TRUE);
     495          priv->need_unset = FALSE;
     496        }
     497
     498      priv->last_notified_clear_area = priv->clear_area;
     499    }
     500
     501  priv->need_position_update = FALSE;
     502  priv->clear_area_idle_id = 0;
     503  return FALSE;
     504}
     505
     506static void
     507_gtk_im_context_check_clear_area (GtkIMContext *context)
     508{
     509  GtkIMContextPrivate *priv;
     510
     511  priv = G_TYPE_INSTANCE_GET_PRIVATE (context, GTK_TYPE_IM_CONTEXT,
     512                                      GtkIMContextPrivate);
     513
     514  if (priv->clear_area_idle_id)
     515    g_source_remove (priv->clear_area_idle_id);
     516
     517  priv->clear_area_idle_id =
     518    gdk_threads_add_idle (_gtk_im_context_clear_area_idle, context);
     519}
     520
     521static void
     522_gtk_im_context_clear_area (GtkIMContext          *context,
     523                            cairo_rectangle_int_t *clear_area,
     524                            cairo_rectangle_int_t *cursor_rect,
     525                            GtkWidget             *widget)
     526{
     527  GtkIMContextPrivate *priv;
     528
     529  priv = G_TYPE_INSTANCE_GET_PRIVATE (context, GTK_TYPE_IM_CONTEXT, GtkIMContextPrivate);
     530
     531  if (priv->clear_area.x != clear_area->x ||
     532      priv->clear_area.y != clear_area->y ||
     533      priv->clear_area.width != clear_area->width ||
     534      priv->clear_area.height != clear_area->height)
     535    priv->need_position_update = TRUE;
     536
     537  priv->clear_area = *clear_area;
     538}
     539
    441540/**
    442541 * gtk_im_context_set_client_window:
    443542 * @context: a #GtkIMContext
    gtk_im_context_set_client_window (GtkIMContext *context, 
    454553                                  GdkWindow    *window)
    455554{
    456555  GtkIMContextClass *klass;
    457  
     556  GtkIMContextPrivate *priv;
     557
    458558  g_return_if_fail (GTK_IS_IM_CONTEXT (context));
    459559
    460560  klass = GTK_IM_CONTEXT_GET_CLASS (context);
    461561  if (klass->set_client_window)
    462562    klass->set_client_window (context, window);
     563
     564  priv = G_TYPE_INSTANCE_GET_PRIVATE (context, GTK_TYPE_IM_CONTEXT, GtkIMContextPrivate);
     565
     566  if (priv->clear_area_signal_id)
     567    {
     568      g_signal_handler_disconnect (context, priv->clear_area_signal_id);
     569      priv->clear_area_signal_id = 0;
     570    }
     571
     572  if (window)
     573    {
     574      gpointer window_data;
     575
     576      gdk_window_get_user_data (window, &window_data);
     577
     578      if (GTK_IS_WIDGET (window_data))
     579        {
     580          priv->clear_area_signal_id = g_signal_connect (context, "clear-area",
     581                                                         G_CALLBACK (_gtk_im_context_clear_area),
     582                                                         window_data);
     583          priv->window = window;
     584          priv->widget = window_data;
     585        }
     586    }
    463587}
    464588
    465589/**
    void 
    531655gtk_im_context_focus_in (GtkIMContext   *context)
    532656{
    533657  GtkIMContextClass *klass;
    534  
     658  GtkIMContextPrivate *priv;
     659
    535660  g_return_if_fail (GTK_IS_IM_CONTEXT (context));
    536661 
    537662  klass = GTK_IM_CONTEXT_GET_CLASS (context);
    538663  if (klass->focus_in)
    539664    klass->focus_in (context);
     665
     666  priv = G_TYPE_INSTANCE_GET_PRIVATE (context, GTK_TYPE_IM_CONTEXT, GtkIMContextPrivate);
     667
     668  if (!priv->focused)
     669    {
     670      priv->focused = TRUE;
     671      priv->need_position_update = TRUE;
     672    }
     673
     674  _gtk_im_context_check_clear_area (context);
    540675}
    541676
    542677/**
    void 
    552687gtk_im_context_focus_out (GtkIMContext   *context)
    553688{
    554689  GtkIMContextClass *klass;
    555  
     690  GtkIMContextPrivate *priv;
     691
    556692  g_return_if_fail (GTK_IS_IM_CONTEXT (context));
    557693
    558694  klass = GTK_IM_CONTEXT_GET_CLASS (context);
    559695  if (klass->focus_out)
    560696    klass->focus_out (context);
     697
     698  priv = G_TYPE_INSTANCE_GET_PRIVATE (context, GTK_TYPE_IM_CONTEXT, GtkIMContextPrivate);
     699
     700  if (priv->focused)
     701    gtk_widget_unset_clear_area (priv->widget, TRUE);
     702
     703  _gtk_im_context_check_clear_area (context);
     704  priv->focused = FALSE;
    561705}
    562706
    563707/**
    gtk_im_context_reset (GtkIMContext *context) 
    575719 
    576720  g_return_if_fail (GTK_IS_IM_CONTEXT (context));
    577721
     722  _gtk_im_context_check_clear_area (context);
     723
    578724  klass = GTK_IM_CONTEXT_GET_CLASS (context);
    579725  if (klass->reset)
    580726    klass->reset (context);
    gtk_im_context_set_cursor_location (GtkIMContext *context, 
    595741                                    const GdkRectangle *area)
    596742{
    597743  GtkIMContextClass *klass;
     744  GtkIMContextPrivate *priv;
    598745 
    599746  g_return_if_fail (GTK_IS_IM_CONTEXT (context));
    600747
     748  priv = G_TYPE_INSTANCE_GET_PRIVATE (context, GTK_TYPE_IM_CONTEXT,
     749                                      GtkIMContextPrivate);
     750
     751  if (priv->cursor_rect.x != area->x ||
     752      priv->cursor_rect.y != area->y ||
     753      priv->cursor_rect.width != area->width ||
     754      priv->cursor_rect.height != area->height)
     755    {
     756      priv->cursor_rect = *area;
     757      priv->need_position_update = TRUE;
     758    }
     759
    601760  klass = GTK_IM_CONTEXT_GET_CLASS (context);
    602761  if (klass->set_cursor_location)
    603762    klass->set_cursor_location (context, (GdkRectangle *) area);
     763
     764  _gtk_im_context_check_clear_area (context);
    604765}
    605766
    606767/**
    gtk_im_context_set_property (GObject *obj, 
    798959      break;
    799960    }
    800961}
     962
     963static void
     964gtk_im_context_finalize (GObject *obj)
     965{
     966  GtkIMContextPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (obj, GTK_TYPE_IM_CONTEXT, GtkIMContextPrivate);
     967
     968  if (priv->clear_area_signal_id)
     969    g_signal_handler_disconnect (obj, priv->clear_area_signal_id);
     970
     971  if (priv->clear_area_idle_id)
     972    g_source_remove (priv->clear_area_idle_id);
     973
     974  G_OBJECT_CLASS (gtk_im_context_parent_class)->finalize (obj);
     975}
  • gtk/gtkimmulticontext.c

    diff --git a/gtk/gtkimmulticontext.c b/gtk/gtkimmulticontext.c
    index 712d5ca..69fba46 100644
    a b static gboolean gtk_im_multicontext_delete_surrounding_cb (GtkIMContext * 
    102102                                                             gint               n_chars,
    103103                                                             GtkIMMulticontext *multicontext);
    104104
     105static void     gtk_im_multicontext_clear_area_cb           (GtkIMContext      *slave,
     106                                                             GdkRectangle      *osk_rect,
     107                                                             GdkRectangle      *cursor_rect,
     108                                                             GtkIMMulticontext *multicontext);
     109
    105110static void propagate_purpose (GtkIMMulticontext *context);
    106111
    107112static const gchar *global_context_id = NULL;
    gtk_im_multicontext_set_slave (GtkIMMulticontext *multicontext, 
    197202      g_signal_handlers_disconnect_by_func (priv->slave,
    198203                                            gtk_im_multicontext_commit_cb,
    199204                                            multicontext);
     205      g_signal_handlers_disconnect_by_func (priv->slave,
     206                                            gtk_im_multicontext_clear_area_cb,
     207                                            multicontext);
    200208
    201209      g_object_unref (priv->slave);
    202210      priv->slave = NULL;
    gtk_im_multicontext_set_slave (GtkIMMulticontext *multicontext, 
    231239      g_signal_connect (priv->slave, "delete-surrounding",
    232240                        G_CALLBACK (gtk_im_multicontext_delete_surrounding_cb),
    233241                        multicontext);
     242      g_signal_connect (priv->slave, "clear-area",
     243                        G_CALLBACK (gtk_im_multicontext_clear_area_cb),
     244                        multicontext);
    234245
    235246      if (!priv->use_preedit)   /* Default is TRUE */
    236247        gtk_im_context_set_use_preedit (slave, FALSE);
    gtk_im_multicontext_delete_surrounding_cb (GtkIMContext *slave, 
    553564}
    554565
    555566static void
     567gtk_im_multicontext_clear_area_cb (GtkIMContext      *slave,
     568                                   GdkRectangle      *osk_rect,
     569                                   GdkRectangle      *cursor_rect,
     570                                   GtkIMMulticontext *multicontext)
     571{
     572  g_signal_emit_by_name (multicontext, "clear-area", osk_rect, cursor_rect);
     573}
     574
     575static void
    556576activate_cb (GtkWidget         *menuitem,
    557577             GtkIMMulticontext *context)
    558578{
  • gtk/gtkscrolledwindow.c

    diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
    index 7929863..6fedf0e 100644
    a b struct _GtkScrolledWindowPrivate 
    175175
    176176  gdouble                unclamped_hadj_value;
    177177  gdouble                unclamped_vadj_value;
     178  gdouble                clear_area_dy;
     179  gdouble                focus_area_dy;
    178180};
    179181
    180182typedef struct
    static gboolean _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindo 
    284286                                                                gboolean           allow_overshooting,
    285287                                                                gboolean           snap_to_border);
    286288
     289static gboolean gtk_scrolled_window_request_clear_area (GtkWidget             *widget,
     290                                                        cairo_rectangle_int_t *clear_area,
     291                                                        cairo_rectangle_int_t *cursor_area,
     292                                                        gpointer               user_data);
     293static gboolean gtk_scrolled_window_unset_clear_area   (GtkWidget             *widget,
     294                                                         gboolean               snap_back,
     295                                                        gpointer               user_data);
     296
    287297static guint signals[LAST_SIGNAL] = {0};
    288298
    289299G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
    gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window) 
    594604  gtk_scrolled_window_update_real_placement (scrolled_window);
    595605  priv->min_content_width = -1;
    596606  priv->min_content_height = -1;
     607  priv->focus_area_dy = 0;
     608  priv->clear_area_dy = 0;
    597609
    598610  gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
    599611  gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
     612
     613  g_signal_connect (scrolled_window, "request-clear-area",
     614                    G_CALLBACK (gtk_scrolled_window_request_clear_area),
     615                    NULL);
     616  g_signal_connect (scrolled_window, "unset-clear-area",
     617                    G_CALLBACK (gtk_scrolled_window_unset_clear_area),
     618                    NULL);
    600619}
    601620
    602621/**
    _gtk_scrolled_window_get_overshoot (GtkScrolledWindow *scrolled_window, 
    18201839
    18211840  if (priv->unclamped_vadj_value < lower)
    18221841    y = priv->unclamped_vadj_value - lower;
    1823   else if (priv->unclamped_vadj_value > upper)
    1824     y = priv->unclamped_vadj_value - upper;
     1842  else if (priv->unclamped_vadj_value + priv->focus_area_dy > upper)
     1843    y = priv->unclamped_vadj_value - upper + priv->focus_area_dy;
    18251844  else
    18261845    y = 0;
    18271846
    _gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_wind 
    18751894    window_allocation.x += -overshoot_x;
    18761895
    18771896  if (overshoot_y < 0)
    1878     window_allocation.y += -overshoot_y;
     1897    {
     1898      window_allocation.y -= priv->focus_area_dy;
     1899      window_allocation.y += -overshoot_y;
     1900    }
    18791901
    18801902  window_allocation.width -= ABS (overshoot_x);
    18811903  window_allocation.height -= ABS (overshoot_y);
    gtk_scrolled_window_size_allocate (GtkWidget *widget, 
    22462268    gtk_widget_hide (priv->vscrollbar);
    22472269
    22482270  _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
     2271  _gtk_scrolled_window_set_adjustment_value (GTK_SCROLLED_WINDOW (widget),
     2272                                             gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)),
     2273                                             priv->unclamped_vadj_value,
     2274                                             TRUE, FALSE);
    22492275}
    22502276
    22512277static gboolean
    _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window, 
    23492375                                           gboolean           snap_to_border)
    23502376{
    23512377  GtkScrolledWindowPrivate *priv = scrolled_window->priv;
    2352   gdouble lower, upper, *prev_value;
     2378  gdouble lower, upper, *prev_value, diff = 0;
    23532379
    23542380  lower = gtk_adjustment_get_lower (adjustment);
    23552381  upper = gtk_adjustment_get_upper (adjustment) -
    _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window, 
    23582384  if (adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)))
    23592385    prev_value = &priv->unclamped_hadj_value;
    23602386  else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)))
    2361     prev_value = &priv->unclamped_vadj_value;
     2387    {
     2388      diff = priv->focus_area_dy;
     2389      upper += priv->clear_area_dy;
     2390      prev_value = &priv->unclamped_vadj_value;
     2391    }
    23622392  else
    23632393    return FALSE;
    23642394
     2395  value += diff;
     2396
    23652397  if (snap_to_border)
    23662398    {
    23672399      if (*prev_value < 0 && value > 0)
    _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window, 
    23762408      upper += MAX_OVERSHOOT_DISTANCE;
    23772409    }
    23782410
    2379   *prev_value = CLAMP (value, lower, upper);
    23802411  gtk_adjustment_set_value (adjustment, value);
     2412  *prev_value = CLAMP (value - diff, lower, upper);
    23812413
    2382   return (*prev_value != value);
     2414  return (*prev_value != value - diff);
    23832415}
    23842416
    23852417static gboolean
    scrolled_window_deceleration_cb (gpointer user_data) 
    24542486  else if (overshoot_x > 0)
    24552487    data->x_velocity -= OVERSHOOT_INVERSE_ACCELERATION * elapsed;
    24562488
    2457   if (overshoot_y == 0)
     2489  if (overshoot_y >= 0 && overshoot_y <= priv->clear_area_dy)
    24582490    {
    2459       if (old_overshoot_y != 0)
     2491      if (old_overshoot_y < 0 || old_overshoot_y > priv->clear_area_dy)
    24602492        {
    24612493          /* Overshooting finished snapping back */
    24622494          data->y_velocity = 0;
    gtk_scrolled_window_captured_button_release (GtkWidget *widget, 
    26202652{
    26212653  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
    26222654  GtkScrolledWindowPrivate *priv = scrolled_window->priv;
     2655  gint overshoot_x, overshoot_y;
    26232656  GtkWidget *child;
    26242657  gboolean overshoot;
    26252658  guint button;
    gtk_scrolled_window_captured_button_release (GtkWidget *widget, 
    26412674      priv->release_timeout_id = 0;
    26422675    }
    26432676
    2644   overshoot = _gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL);
     2677  overshoot = _gtk_scrolled_window_get_overshoot (scrolled_window, &overshoot_x, &overshoot_y);
    26452678
    26462679  if (priv->in_drag)
    26472680    gdk_device_ungrab (gdk_event_get_device (event), gdk_event_get_time (event));
    gtk_scrolled_window_captured_button_release (GtkWidget *widget, 
    26522685       */
    26532686      gtk_scrolled_window_release_captured_event (scrolled_window);
    26542687
    2655       if (!overshoot)
     2688      if (!overshoot ||
     2689          (overshoot_x == 0 && overshoot_y >= 0 &&
     2690           overshoot_y <= priv->clear_area_dy))
    26562691        return FALSE;
    26572692    }
    26582693  priv->in_drag = FALSE;
    gtk_scrolled_window_captured_motion_notify (GtkWidget *widget, 
    27662801  vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
    27672802  if (vadjustment && priv->vscrollbar_visible)
    27682803    {
    2769       dy = (priv->last_motion_event_y_root - y_root) + priv->unclamped_vadj_value;
     2804      dy = (priv->last_motion_event_y_root - y_root) + priv->unclamped_vadj_value + priv->focus_area_dy;
    27702805      _gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment,
    27712806                                                 dy, TRUE, FALSE);
    27722807    }
    27732808
     2809  priv->focus_area_dy = 0;
    27742810  _gtk_scrolled_window_get_overshoot (scrolled_window,
    27752811                                      &new_overshoot_x, &new_overshoot_y);
    27762812
    gtk_scrolled_window_grab_notify (GtkWidget *widget, 
    34573493    }
    34583494}
    34593495
     3496static gboolean
     3497gtk_scrolled_window_request_clear_area (GtkWidget             *widget,
     3498                                        cairo_rectangle_int_t *clear_area,
     3499                                        cairo_rectangle_int_t *cursor_area,
     3500                                        gpointer               user_data)
     3501{
     3502  gdouble clear_area_dy, focus_area_dy;
     3503  GtkScrolledWindowPrivate *priv;
     3504  GtkAdjustment *adjustment;
     3505  GtkAllocation allocation;
     3506
     3507  priv = GTK_SCROLLED_WINDOW (widget)->priv;
     3508  adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
     3509
     3510  gtk_widget_get_allocation (widget, &allocation);
     3511  allocation.x = allocation.y = 0;
     3512
     3513  gdk_window_get_root_coords (gtk_widget_get_window (widget),
     3514                              allocation.x, allocation.y,
     3515                              &allocation.x, &allocation.y);
     3516
     3517  if (clear_area->y > allocation.y + allocation.height ||
     3518      clear_area->y + clear_area->height < allocation.y)
     3519    return FALSE;
     3520
     3521  clear_area_dy = allocation.y + allocation.height - clear_area->y;
     3522  focus_area_dy = cursor_area->y + cursor_area->height - clear_area->y;
     3523
     3524  if (focus_area_dy <= 0)
     3525    return TRUE;
     3526
     3527  priv->clear_area_dy = clear_area_dy;
     3528  priv->focus_area_dy = focus_area_dy;
     3529  _gtk_scrolled_window_set_adjustment_value (GTK_SCROLLED_WINDOW (widget),
     3530                                             adjustment, priv->unclamped_vadj_value,
     3531                                             TRUE, FALSE);
     3532  gtk_widget_queue_resize (widget);
     3533
     3534  return TRUE;
     3535}
     3536
     3537static gboolean
     3538gtk_scrolled_window_unset_clear_area (GtkWidget *widget,
     3539                                      gboolean   snap_back,
     3540                                      gpointer   user_data)
     3541{
     3542  GtkScrolledWindowPrivate *priv;
     3543
     3544  priv = GTK_SCROLLED_WINDOW (widget)->priv;
     3545
     3546  if (priv->clear_area_dy != 0 || priv->focus_area_dy != 0)
     3547    {
     3548      priv->clear_area_dy = 0;
     3549      priv->focus_area_dy = 0;
     3550
     3551      if (snap_back)
     3552        {
     3553          GtkAdjustment *adjustment;
     3554
     3555          adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
     3556          _gtk_scrolled_window_set_adjustment_value (GTK_SCROLLED_WINDOW (widget),
     3557                                                     adjustment, priv->unclamped_vadj_value,
     3558                                                     FALSE, FALSE);
     3559          gtk_widget_queue_resize (widget);
     3560        }
     3561
     3562      return TRUE;
     3563    }
     3564
     3565  return FALSE;
     3566}
     3567
    34603568/**
    34613569 * gtk_scrolled_window_get_min_content_width:
    34623570 * @scrolled_window: a #GtkScrolledWindow
  • gtk/gtkwidget.c

    diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
    index 7ff2424..5a88ae0 100644
    a b enum { 
    484484  DRAG_FAILED,
    485485  STYLE_UPDATED,
    486486  TOUCH_EVENT,
     487  REQUEST_CLEAR_AREA,
     488  UNSET_CLEAR_AREA,
    487489  LAST_SIGNAL
    488490};
    489491
    gtk_widget_class_init (GtkWidgetClass *klass) 
    31203122                  _gtk_marshal_BOOLEAN__UINT,
    31213123                  G_TYPE_BOOLEAN, 1, G_TYPE_UINT);
    31223124
     3125  widget_signals[REQUEST_CLEAR_AREA] =
     3126    g_signal_new (I_("request-clear-area"),
     3127                  G_TYPE_FROM_CLASS (klass),
     3128                  G_SIGNAL_RUN_LAST, 0,
     3129                  g_signal_accumulator_true_handled, NULL,
     3130                  _gtk_marshal_BOOLEAN__BOXED_BOXED,
     3131                  G_TYPE_BOOLEAN, 2,
     3132                  CAIRO_GOBJECT_TYPE_RECTANGLE_INT,
     3133                  CAIRO_GOBJECT_TYPE_RECTANGLE_INT);
     3134  widget_signals[UNSET_CLEAR_AREA] =
     3135    g_signal_new (I_("unset-clear-area"),
     3136                  G_TYPE_FROM_CLASS (klass),
     3137                  G_SIGNAL_RUN_LAST, 0,
     3138                  g_signal_accumulator_true_handled, NULL,
     3139                  _gtk_marshal_BOOLEAN__BOOLEAN,
     3140                  G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN);
     3141
    31233142  binding_set = gtk_binding_set_by_class (klass);
    31243143  gtk_binding_entry_add_signal (binding_set, GDK_KEY_F10, GDK_SHIFT_MASK,
    31253144                                "popup-menu", 0);
    gtk_widget_insert_action_group (GtkWidget *widget, 
    1413914158  else
    1414014159    g_action_muxer_remove (muxer, name);
    1414114160}
     14161
     14162gboolean
     14163gtk_widget_request_clear_area (GtkWidget             *widget,
     14164                               cairo_rectangle_int_t *clear_area,
     14165                               cairo_rectangle_int_t *cursor_position)
     14166{
     14167  gboolean handled = FALSE;
     14168  GtkWidget *cur;
     14169
     14170  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
     14171  g_return_val_if_fail (cursor_position != NULL, FALSE);
     14172  g_return_val_if_fail (clear_area != NULL, FALSE);
     14173
     14174  cur = widget;
     14175
     14176  while (!handled && cur)
     14177    {
     14178      g_signal_emit (cur, widget_signals[REQUEST_CLEAR_AREA], 0,
     14179                     clear_area, cursor_position, &handled);
     14180
     14181      if (!handled)
     14182        cur = gtk_widget_get_parent (cur);
     14183    }
     14184
     14185  return handled;
     14186}
     14187
     14188gboolean
     14189gtk_widget_unset_clear_area (GtkWidget *widget,
     14190                             gboolean   snap_back)
     14191{
     14192  gboolean handled = FALSE;
     14193  GtkWidget *cur;
     14194
     14195  cur = widget;
     14196
     14197  while (!handled && cur)
     14198    {
     14199      g_signal_emit (cur, widget_signals[UNSET_CLEAR_AREA], 0,
     14200                     snap_back, &handled);
     14201
     14202      if (!handled)
     14203        cur = gtk_widget_get_parent (cur);
     14204    }
     14205
     14206  return handled;
     14207}
  • gtk/gtkwidget.h

    diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
    index c178478..ce4f4dc 100644
    a b GDK_AVAILABLE_IN_3_4 
    886886GdkModifierType   gtk_widget_get_modifier_mask (GtkWidget         *widget,
    887887                                                GdkModifierIntent  intent);
    888888
     889gboolean gtk_widget_request_clear_area (GtkWidget             *widget,
     890                                        cairo_rectangle_int_t *clear_area,
     891                                        cairo_rectangle_int_t *cursor_position);
     892gboolean gtk_widget_unset_clear_area   (GtkWidget             *widget,
     893                                        gboolean               snap_back);
     894
    889895GDK_AVAILABLE_IN_3_6
    890896void                    gtk_widget_insert_action_group                  (GtkWidget    *widget,
    891897                                                                         const gchar  *name,