~inkscape.dev/inkscape/RELEASE_0_91_BRANCH

« back to all changes in this revision

Viewing changes to src/widgets/ruler.cpp

  • Committer: JazzyNico
  • Author(s): Eduard Braun (eduard-braun2)
  • Date: 2016-02-27 17:34:29 UTC
  • Revision ID: nicoduf@yahoo.fr-20160227173429-x5knoml14q7t2bat
UI. Fix for bug #1351597 (Inkscape + Cairo >= 1.12 very slow on Windows, unless rulers are hidden).

Show diffs side-by-side

added added

removed removed

Lines of Context:
41
41
 
42
42
#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
43
43
 
44
 
#define DEFAULT_RULER_FONT_SCALE  PANGO_SCALE_X_SMALL
45
 
#define MINIMUM_INCR              5
 
44
#define DEFAULT_RULER_FONT_SCALE    PANGO_SCALE_X_SMALL
 
45
#define MINIMUM_INCR                5
 
46
#define IMMEDIATE_REDRAW_THRESHOLD  20
46
47
 
47
48
using Inkscape::Util::unit_table;
48
49
 
71
72
 
72
73
  GdkWindow       *input_window;
73
74
  cairo_surface_t *backing_store;
 
75
  gboolean         backing_store_valid;
 
76
  GdkRectangle     last_pos_rect;
 
77
  guint            pos_redraw_idle_id;
74
78
  PangoLayout     *layout;
75
79
  gdouble          font_scale;
76
 
  
77
 
  gint             xsrc;
78
 
  gint             ysrc;
79
80
 
80
81
  GList           *track_widgets;
81
82
} SPRulerPrivate;
132
133
static void          sp_ruler_size_request         (GtkWidget      *widget,
133
134
                                                    GtkRequisition *requisition);
134
135
static void          sp_ruler_style_set            (GtkWidget      *widget,
135
 
                                                    GtkStyle       *prev_style);
 
136
                                                    GtkStyle       *prev_style);
136
137
#endif
137
138
 
138
139
static gboolean      sp_ruler_motion_notify        (GtkWidget      *widget,
139
140
                                                    GdkEventMotion *event);
140
141
static gboolean      sp_ruler_draw                 (GtkWidget      *widget,
141
 
                                                    cairo_t        *cr);
 
142
                                                    cairo_t        *cr);
142
143
#if !GTK_CHECK_VERSION(3,0,0)
143
144
static gboolean      sp_ruler_expose               (GtkWidget      *widget,
144
145
                                                    GdkEventExpose *event);
145
146
#endif
146
147
static void          sp_ruler_draw_ticks           (SPRuler        *ruler);
147
 
static void          sp_ruler_draw_pos             (SPRuler        *ruler);
 
148
static GdkRectangle  sp_ruler_get_pos_rect         (SPRuler        *ruler,
 
149
                                                    gdouble         position);
 
150
static gboolean      sp_ruler_idle_queue_pos_redraw(gpointer        data);
 
151
static void          sp_ruler_queue_pos_redraw     (SPRuler        *ruler);
 
152
static void          sp_ruler_draw_pos             (SPRuler        *ruler,
 
153
                                                    cairo_t        *cr);
148
154
static void          sp_ruler_make_pixmap          (SPRuler        *ruler);
149
155
 
150
156
static PangoLayout * sp_ruler_get_layout           (GtkWidget      *widget,
259
265
 
260
266
  gtk_widget_set_has_window (GTK_WIDGET (ruler), FALSE);
261
267
 
262
 
  priv->orientation   = GTK_ORIENTATION_HORIZONTAL;
263
 
  priv->unit          = unit_table.getUnit("px");
264
 
  priv->lower         = 0;
265
 
  priv->upper         = 0;
266
 
  priv->position      = 0;
267
 
  priv->max_size      = 0;
268
 
  priv->backing_store = NULL;
269
 
  priv->font_scale    = DEFAULT_RULER_FONT_SCALE;
 
268
  priv->orientation          = GTK_ORIENTATION_HORIZONTAL;
 
269
  priv->unit                 = unit_table.getUnit("px");
 
270
  priv->lower                = 0;
 
271
  priv->upper                = 0;
 
272
  priv->position             = 0;
 
273
  priv->max_size             = 0;
 
274
 
 
275
  priv->backing_store        = NULL;
 
276
  priv->backing_store_valid  = FALSE;
 
277
 
 
278
  priv->last_pos_rect.x      = 0;
 
279
  priv->last_pos_rect.y      = 0;
 
280
  priv->last_pos_rect.width  = 0;
 
281
  priv->last_pos_rect.height = 0;
 
282
  priv->pos_redraw_idle_id   = 0;
 
283
 
 
284
  priv->font_scale           = DEFAULT_RULER_FONT_SCALE;
270
285
 
271
286
#if GTK_CHECK_VERSION(3,0,0)
272
287
  #if GTK_CHECK_VERSION(3,8,0)
298
313
  while (priv->track_widgets)
299
314
    sp_ruler_remove_track_widget (ruler, GTK_WIDGET(priv->track_widgets->data));
300
315
 
 
316
  if (priv->pos_redraw_idle_id)
 
317
    {
 
318
      g_source_remove (priv->pos_redraw_idle_id);
 
319
      priv->pos_redraw_idle_id = 0;
 
320
    }
 
321
 
301
322
  G_OBJECT_CLASS (parent_class)->dispose (object);
302
323
}
303
324
 
342
363
    }
343
364
  g_object_thaw_notify (G_OBJECT (ruler));
344
365
 
 
366
  priv->backing_store_valid = FALSE;
345
367
  gtk_widget_queue_draw (GTK_WIDGET (ruler));
346
368
}
347
369
 
512
534
      cairo_surface_destroy (priv->backing_store);
513
535
      priv->backing_store = NULL;
514
536
    }
515
 
  
 
537
 
 
538
  priv->backing_store_valid = FALSE;
 
539
 
516
540
  if (priv->layout)
517
541
    {
518
542
      g_object_unref (priv->layout);
688
712
    cairo_clip (cr);
689
713
 
690
714
    gtk_widget_get_allocation (widget, &allocation);
691
 
    cairo_translate (cr, allocation.x, allocation.y);
692
715
 
693
716
    gboolean result = sp_ruler_draw (widget, cr);
694
717
 
710
733
  cairo_set_source_surface(cr, priv->backing_store, 0, 0);
711
734
  cairo_paint(cr);
712
735
 
713
 
  sp_ruler_draw_pos (ruler);
 
736
  sp_ruler_draw_pos (ruler, cr);
714
737
 
715
738
  return FALSE;
716
739
}
732
755
                                       CAIRO_CONTENT_COLOR,
733
756
                                       allocation.width,
734
757
                                       allocation.height);
 
758
 
 
759
  priv->backing_store_valid = FALSE;
735
760
}
736
761
 
737
762
static void
738
 
sp_ruler_draw_pos (SPRuler *ruler)
 
763
sp_ruler_draw_pos (SPRuler *ruler,
 
764
                   cairo_t *cr)
739
765
{
740
766
  GtkWidget       *widget  = GTK_WIDGET (ruler);
741
767
 
742
768
#if GTK_CHECK_VERSION(3,0,0)
743
769
  GtkStyleContext *context = gtk_widget_get_style_context (widget);
744
 
  GtkBorder        border;
745
770
  GdkRGBA          color;
746
771
#else
747
772
  GtkStyle        *style   = gtk_widget_get_style (widget);
748
773
  GtkStateType     state   = gtk_widget_get_state (widget);
749
 
  gint             xthickness;
750
 
  gint             ythickness;
751
774
#endif
752
775
  
753
776
  SPRulerPrivate  *priv    = SP_RULER_GET_PRIVATE (ruler);
754
 
  GtkAllocation    allocation;
755
 
  gint             x, y;
756
 
  gint             width, height;
757
 
  gint             bs_width, bs_height;
 
777
  GdkRectangle      pos_rect;
758
778
 
759
779
  if (! gtk_widget_is_drawable (widget))
760
780
      return;
761
781
 
762
 
  gtk_widget_get_allocation(widget, &allocation);
763
 
 
764
 
#if GTK_CHECK_VERSION(3,0,0)
765
 
  gtk_style_context_get_border (context, static_cast<GtkStateFlags>(0), &border);
766
 
#else
767
 
  xthickness = style->xthickness;
768
 
  ythickness = style->ythickness;
769
 
#endif
770
 
 
771
 
  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
772
 
    {
773
 
      width  = allocation.width;
774
 
#if GTK_CHECK_VERSION(3,0,0)
775
 
      height = allocation.height - (border.top + border.bottom);
776
 
#else
777
 
      height = allocation.height - ythickness * 2;
778
 
#endif
779
 
 
780
 
      bs_width = height / 2 + 2;
781
 
      bs_width |= 1;  /* make sure it's odd */
782
 
      bs_height = bs_width / 2 + 1;
783
 
    }
784
 
  else
785
 
    {
786
 
#if GTK_CHECK_VERSION(3,0,0)
787
 
      width  = allocation.width - (border.left + border.right);
788
 
#else
789
 
      width  = allocation.width - xthickness * 2;
790
 
#endif
791
 
      height = allocation.height;
792
 
 
793
 
      bs_height = width / 2 + 2;
794
 
      bs_height |= 1;  /* make sure it's odd */
795
 
      bs_width = bs_height / 2 + 1;
796
 
    }
797
 
 
798
 
  if ((bs_width > 0) && (bs_height > 0))
799
 
    {
800
 
      cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
801
 
      gdouble lower;
802
 
      gdouble upper;
803
 
      gdouble position;
804
 
      gdouble increment;
805
 
 
806
 
      cairo_rectangle (cr,
807
 
                       allocation.x, allocation.y,
808
 
                       allocation.width, allocation.height);
809
 
      cairo_clip (cr);
810
 
 
811
 
      cairo_translate (cr, allocation.x, allocation.y);
812
 
 
813
 
      /* If a backing store exists, restore the ruler  */
814
 
      if (priv->backing_store)
815
 
        {
816
 
          cairo_set_source_surface (cr, priv->backing_store, 0, 0);
817
 
          cairo_rectangle (cr, priv->xsrc, priv->ysrc, bs_width, bs_height);
818
 
          cairo_fill (cr);
819
 
        }
820
 
 
821
 
      position = sp_ruler_get_position (ruler);
822
 
 
823
 
      sp_ruler_get_range (ruler, &lower, &upper, NULL);
824
 
 
825
 
      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
826
 
        {
827
 
          increment = (gdouble) width / (upper - lower);
828
 
 
829
 
#if GTK_CHECK_VERSION(3,0,0)
830
 
          x = ROUND ((position - lower) * increment) + (border.left - bs_width) / 2 - 1;
831
 
          y = (height + bs_height) / 2 + border.top;
832
 
#else
833
 
          x = ROUND ((position - lower) * increment) + (xthickness - bs_width) / 2 - 1;
834
 
          y = (height + bs_height) / 2 + ythickness;
835
 
#endif
836
 
        }
837
 
      else
838
 
        {
839
 
          increment = (gdouble) height / (upper - lower);
840
 
 
841
 
#if GTK_CHECK_VERSION(3,0,0)
842
 
          x = (width + bs_width) / 2 + border.left;
843
 
          y = ROUND ((position - lower) * increment) + (border.top - bs_height) / 2 - 1;
844
 
#else
845
 
          x = (width + bs_width) / 2 + xthickness;
846
 
          y = ROUND ((position - lower) * increment) + (ythickness - bs_height) / 2 - 1;
847
 
#endif
848
 
        }
849
 
 
 
782
  pos_rect = sp_ruler_get_pos_rect (ruler, sp_ruler_get_position (ruler));
 
783
 
 
784
  if ((pos_rect.width > 0) && (pos_rect.height > 0))
 
785
    {
850
786
#if GTK_CHECK_VERSION(3,0,0)
851
787
      gtk_style_context_get_color (context, gtk_widget_get_state_flags (widget),
852
788
                                   &color);
855
791
      gdk_cairo_set_source_color (cr, &style->fg[state]);
856
792
#endif
857
793
 
858
 
      cairo_move_to (cr, x, y);
 
794
      cairo_move_to (cr, pos_rect.x, pos_rect.y);
859
795
 
860
796
      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
861
797
        {
862
 
          cairo_line_to (cr, x + bs_width / 2.0, y + bs_height);
863
 
          cairo_line_to (cr, x + bs_width,       y);
 
798
          cairo_line_to (cr, pos_rect.x + pos_rect.width / 2.0,
 
799
                             pos_rect.y + pos_rect.height);
 
800
          cairo_line_to (cr, pos_rect.x + pos_rect.width,
 
801
                             pos_rect.y);
864
802
        }
865
803
      else
866
804
        {
867
 
          cairo_line_to (cr, x + bs_width, y + bs_height / 2.0);
868
 
          cairo_line_to (cr, x,            y + bs_height);
 
805
          cairo_line_to (cr, pos_rect.x + pos_rect.width,
 
806
 
 
807
                             pos_rect.y + pos_rect.height / 2.0);
 
808
          cairo_line_to (cr, pos_rect.x,
 
809
                             pos_rect.y + pos_rect.height);
869
810
        }
870
811
 
871
812
      cairo_fill (cr);
872
 
 
873
 
      cairo_destroy (cr);
874
 
 
875
 
      priv->xsrc = x;
876
 
      priv->ysrc = y;
877
813
    }
 
814
 
 
815
  priv->last_pos_rect = pos_rect;
878
816
}
879
817
 
880
818
/**
1088
1026
      priv->unit = unit;
1089
1027
      g_object_notify(G_OBJECT(ruler), "unit");
1090
1028
 
 
1029
      priv->backing_store_valid = FALSE;
1091
1030
      gtk_widget_queue_draw (GTK_WIDGET (ruler));
1092
1031
    }
1093
1032
}
1123
1062
 
1124
1063
    if (priv->position != position)
1125
1064
    {
1126
 
        priv->position = position;
1127
 
        g_object_notify (G_OBJECT (ruler), "position");
1128
 
 
1129
 
        sp_ruler_draw_pos (ruler);
 
1065
      GdkRectangle rect;
 
1066
      gint xdiff, ydiff;
 
1067
 
 
1068
      priv->position = position;
 
1069
      g_object_notify (G_OBJECT (ruler), "position");
 
1070
 
 
1071
      rect = sp_ruler_get_pos_rect (ruler, priv->position);
 
1072
 
 
1073
      xdiff = rect.x - priv->last_pos_rect.x;
 
1074
      ydiff = rect.y - priv->last_pos_rect.y;
 
1075
 
 
1076
      /*
 
1077
       * If the position has changed far enough, queue a redraw immediately.
 
1078
       * Otherwise, we only queue a redraw in a low priority idle handler, to
 
1079
       * allow for other things (like updating the canvas) to run.
 
1080
       *
 
1081
       * TODO: This might not be necessary any more in GTK3 with the frame
 
1082
       *       clock. Investigate this more after the port to GTK3.
 
1083
       */
 
1084
      if (priv->last_pos_rect.width  != 0 &&
 
1085
          priv->last_pos_rect.height != 0 &&
 
1086
          (ABS (xdiff) > IMMEDIATE_REDRAW_THRESHOLD ||
 
1087
           ABS (ydiff) > IMMEDIATE_REDRAW_THRESHOLD))
 
1088
        {
 
1089
          sp_ruler_queue_pos_redraw (ruler);
 
1090
        }
 
1091
      else if (! priv->pos_redraw_idle_id)
 
1092
        {
 
1093
          priv->pos_redraw_idle_id =
 
1094
            g_idle_add_full (G_PRIORITY_LOW,
 
1095
                             sp_ruler_idle_queue_pos_redraw,
 
1096
                             ruler, NULL);
 
1097
        }
1130
1098
    }
1131
1099
}
1132
1100
 
1446
1414
 
1447
1415
    cairo_fill (cr);
1448
1416
 
 
1417
  priv->backing_store_valid = TRUE;
 
1418
 
1449
1419
out:
1450
1420
    cairo_destroy (cr);
1451
1421
}
1452
1422
 
 
1423
static GdkRectangle
 
1424
sp_ruler_get_pos_rect (SPRuler *ruler,
 
1425
                       gdouble  position)
 
1426
{
 
1427
  GtkWidget        *widget = GTK_WIDGET (ruler);
 
1428
  GtkStyle         *style  = gtk_widget_get_style (widget);
 
1429
  SPRulerPrivate   *priv   = SP_RULER_GET_PRIVATE (ruler);
 
1430
  GtkAllocation     allocation;
 
1431
  gint              width, height;
 
1432
  gint              xthickness;
 
1433
  gint              ythickness;
 
1434
  gdouble           upper, lower;
 
1435
  gdouble           increment;
 
1436
  GdkRectangle      rect = { 0, };
 
1437
 
 
1438
  if (! gtk_widget_is_drawable (widget))
 
1439
    return rect;
 
1440
 
 
1441
  gtk_widget_get_allocation (widget, &allocation);
 
1442
 
 
1443
  xthickness = style->xthickness;
 
1444
  ythickness = style->ythickness;
 
1445
 
 
1446
  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
 
1447
    {
 
1448
      width  = allocation.width;
 
1449
      height = allocation.height - ythickness * 2;
 
1450
 
 
1451
      rect.width = height / 2 + 2;
 
1452
      rect.width |= 1;  /* make sure it's odd */
 
1453
      rect.height = rect.width / 2 + 1;
 
1454
    }
 
1455
  else
 
1456
    {
 
1457
      width  = allocation.width - xthickness * 2;
 
1458
      height = allocation.height;
 
1459
 
 
1460
      rect.height = width / 2 + 2;
 
1461
      rect.height |= 1;  /* make sure it's odd */
 
1462
      rect.width = rect.height / 2 + 1;
 
1463
    }
 
1464
 
 
1465
  sp_ruler_get_range (ruler, &lower, &upper, NULL);
 
1466
 
 
1467
  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
 
1468
    {
 
1469
      increment = (gdouble) width / (upper - lower);
 
1470
 
 
1471
      rect.x = ROUND ((position - lower) * increment) + (xthickness - rect.width) / 2 - 1;
 
1472
      rect.y = (height + rect.height) / 2 + ythickness;
 
1473
    }
 
1474
  else
 
1475
    {
 
1476
      increment = (gdouble) height / (upper - lower);
 
1477
 
 
1478
      rect.x = (width + rect.width) / 2 + xthickness;
 
1479
      rect.y = ROUND ((position - lower) * increment) + (ythickness - rect.height) / 2 - 1;
 
1480
    }
 
1481
 
 
1482
  rect.x += allocation.x;
 
1483
  rect.y += allocation.y;
 
1484
 
 
1485
  return rect;
 
1486
}
 
1487
 
 
1488
static gboolean
 
1489
sp_ruler_idle_queue_pos_redraw (gpointer data)
 
1490
{
 
1491
  SPRuler        *ruler = (SPRuler *)data;
 
1492
  SPRulerPrivate *priv  = SP_RULER_GET_PRIVATE (ruler);
 
1493
 
 
1494
  sp_ruler_queue_pos_redraw (ruler);
 
1495
 
 
1496
  gboolean ret = g_source_remove(priv->pos_redraw_idle_id);
 
1497
  priv->pos_redraw_idle_id = 0;
 
1498
 
 
1499
  return ret;
 
1500
}
 
1501
 
 
1502
static void
 
1503
sp_ruler_queue_pos_redraw (SPRuler *ruler)
 
1504
{
 
1505
  SPRulerPrivate    *priv = SP_RULER_GET_PRIVATE (ruler);
 
1506
  const GdkRectangle rect = sp_ruler_get_pos_rect (ruler, priv->position);
 
1507
 
 
1508
  gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
 
1509
                              rect.x,
 
1510
                              rect.y,
 
1511
                              rect.width,
 
1512
                              rect.height);
 
1513
 
 
1514
  if (priv->last_pos_rect.width != 0 || priv->last_pos_rect.height != 0)
 
1515
    {
 
1516
      gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
 
1517
                                  priv->last_pos_rect.x,
 
1518
                                  priv->last_pos_rect.y,
 
1519
                                  priv->last_pos_rect.width,
 
1520
                                  priv->last_pos_rect.height);
 
1521
 
 
1522
      priv->last_pos_rect.x      = 0;
 
1523
      priv->last_pos_rect.y      = 0;
 
1524
      priv->last_pos_rect.width  = 0;
 
1525
      priv->last_pos_rect.height = 0;
 
1526
    }
 
1527
}
 
1528
 
1453
1529
static PangoLayout*
1454
1530
sp_ruler_create_layout (GtkWidget   *widget,
1455
1531
                        const gchar *text)