From 9bfc81a58c6ddde2d0e7c9c48f31dbe5354f0b64 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlos@lanedo.com>
Date: Wed, 7 Nov 2012 14:23:04 +0100
Subject: [PATCH] texthandles: Keep state internally to avoid X overhead
Handles now do sync X calls less often. As visibility state
is kept, it now can move+resize+show handles at once instead
of in separated steps.
---
gtk/gtktexthandle.c | 130 +++++++++++++++++++++++++++++-----------------------
1 file changed, 73 insertions(+), 57 deletions(-)
diff --git a/gtk/gtktexthandle.c b/gtk/gtktexthandle.c
index 6c7033b..426fa3a 100644
a
|
b
|
struct _HandleWindow |
46 | 46 | gint dx; |
47 | 47 | gint dy; |
48 | 48 | guint dragged : 1; |
| 49 | guint mode_visible : 1; |
| 50 | guint user_visible : 1; |
| 51 | guint has_point : 1; |
49 | 52 | }; |
50 | 53 | |
51 | 54 | struct _GtkTextHandlePrivate |
… |
… |
gtk_text_handle_widget_event (GtkWidget *widget, |
278 | 281 | } |
279 | 282 | |
280 | 283 | static void |
281 | | _gtk_text_handle_update_window (GtkTextHandle *handle, |
282 | | GtkTextHandlePosition pos) |
| 284 | _gtk_text_handle_update_window_state (GtkTextHandle *handle, |
| 285 | GtkTextHandlePosition pos) |
283 | 286 | { |
284 | 287 | GtkTextHandlePrivate *priv; |
285 | 288 | HandleWindow *handle_window; |
286 | | gboolean visible; |
287 | | gint x, y; |
288 | 289 | |
289 | 290 | priv = handle->priv; |
290 | 291 | handle_window = &priv->windows[pos]; |
… |
… |
_gtk_text_handle_update_window (GtkTextHandle *handle, |
292 | 293 | if (!handle_window->window) |
293 | 294 | return; |
294 | 295 | |
295 | | /* Get current state and destroy */ |
296 | | visible = gdk_window_is_visible (handle_window->window); |
297 | | |
298 | | if (visible) |
| 296 | if (handle_window->has_point && |
| 297 | handle_window->mode_visible && handle_window->user_visible) |
299 | 298 | { |
300 | | gint width; |
| 299 | gint x, y, width, height; |
301 | 300 | |
302 | | _gtk_text_handle_get_size (handle, &width, NULL); |
303 | | gdk_window_get_root_coords (handle_window->window, |
304 | | width / 2, 0, &x, &y); |
| 301 | x = handle_window->pointing_to.x; |
| 302 | y = handle_window->pointing_to.y; |
| 303 | _gtk_text_handle_get_size (handle, &width, &height); |
| 304 | |
| 305 | if (pos == GTK_TEXT_HANDLE_POSITION_CURSOR) |
| 306 | y += handle_window->pointing_to.height; |
| 307 | else |
| 308 | y -= height; |
| 309 | |
| 310 | x -= width / 2; |
| 311 | |
| 312 | gdk_window_move_resize (handle_window->window, x, y, width, height); |
| 313 | gdk_window_show (handle_window->window); |
305 | 314 | } |
| 315 | else |
| 316 | gdk_window_hide (handle_window->window); |
| 317 | } |
306 | 318 | |
307 | | gdk_window_destroy (handle_window->window); |
| 319 | static void |
| 320 | _gtk_text_handle_update_window (GtkTextHandle *handle, |
| 321 | GtkTextHandlePosition pos, |
| 322 | gboolean recreate) |
| 323 | { |
| 324 | GtkTextHandlePrivate *priv; |
| 325 | HandleWindow *handle_window; |
| 326 | gboolean visible; |
| 327 | gint x, y; |
| 328 | |
| 329 | priv = handle->priv; |
| 330 | handle_window = &priv->windows[pos]; |
308 | 331 | |
309 | | /* Create new window and apply old state */ |
310 | | handle_window->window = _gtk_text_handle_create_window (handle, pos); |
| 332 | if (!handle_window->window) |
| 333 | return; |
311 | 334 | |
312 | | if (visible) |
| 335 | if (recreate) |
313 | 336 | { |
314 | | gdk_window_show (handle_window->window); |
315 | | _gtk_text_handle_set_position (handle, pos, |
316 | | &handle_window->pointing_to); |
| 337 | gdk_window_destroy (handle_window->window); |
| 338 | handle_window->window = _gtk_text_handle_create_window (handle, pos); |
317 | 339 | } |
| 340 | |
| 341 | _gtk_text_handle_update_window_state (handle, pos); |
318 | 342 | } |
319 | 343 | |
320 | 344 | static void |
… |
… |
_gtk_text_handle_update_windows (GtkTextHandle *handle) |
323 | 347 | GtkTextHandlePrivate *priv = handle->priv; |
324 | 348 | |
325 | 349 | gtk_style_context_invalidate (priv->style_context); |
326 | | _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START); |
327 | | _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END); |
| 350 | _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START, FALSE); |
| 351 | _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END, FALSE); |
| 352 | } |
| 353 | |
| 354 | static void |
| 355 | _gtk_text_handle_composited_changed (GtkTextHandle *handle) |
| 356 | { |
| 357 | _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START, TRUE); |
| 358 | _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END, TRUE); |
328 | 359 | } |
329 | 360 | |
330 | 361 | static void |
… |
… |
gtk_text_handle_constructed (GObject *object) |
345 | 376 | object); |
346 | 377 | priv->composited_changed_id = |
347 | 378 | g_signal_connect_swapped (priv->parent, "composited-changed", |
348 | | G_CALLBACK (_gtk_text_handle_update_windows), |
| 379 | G_CALLBACK (_gtk_text_handle_composited_changed), |
349 | 380 | object); |
350 | 381 | priv->style_updated_id = |
351 | 382 | g_signal_connect_swapped (priv->parent, "style-updated", |
… |
… |
_gtk_text_handle_set_mode (GtkTextHandle *handle, |
560 | 591 | if (priv->mode == mode) |
561 | 592 | return; |
562 | 593 | |
| 594 | priv->mode = mode; |
| 595 | |
563 | 596 | switch (mode) |
564 | 597 | { |
565 | 598 | case GTK_TEXT_HANDLE_MODE_CURSOR: |
566 | | /* Only display one handle */ |
567 | | gdk_window_show (priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].window); |
568 | | gdk_window_hide (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); |
| 599 | priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].mode_visible = TRUE; |
| 600 | priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = FALSE; |
569 | 601 | break; |
570 | | case GTK_TEXT_HANDLE_MODE_SELECTION: |
571 | | /* Display both handles */ |
572 | | gdk_window_show (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); |
573 | | gdk_window_show (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window); |
| 602 | case GTK_TEXT_HANDLE_MODE_SELECTION: |
| 603 | priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = TRUE; |
| 604 | priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].mode_visible = TRUE; |
574 | 605 | break; |
575 | 606 | case GTK_TEXT_HANDLE_MODE_NONE: |
576 | 607 | default: |
577 | | gdk_window_hide (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); |
578 | | gdk_window_hide (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window); |
| 608 | priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = FALSE; |
| 609 | priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].mode_visible = FALSE; |
579 | 610 | break; |
580 | 611 | } |
581 | 612 | |
582 | | priv->mode = mode; |
583 | | |
584 | 613 | _gtk_text_handle_update_shape (handle, |
585 | 614 | priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].window, |
586 | 615 | GTK_TEXT_HANDLE_POSITION_CURSOR); |
| 616 | |
| 617 | _gtk_text_handle_update_window_state (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START); |
| 618 | _gtk_text_handle_update_window_state (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END); |
587 | 619 | } |
588 | 620 | |
589 | 621 | GtkTextHandleMode |
… |
… |
_gtk_text_handle_set_position (GtkTextHandle *handle, |
611 | 643 | priv = handle->priv; |
612 | 644 | pos = CLAMP (pos, GTK_TEXT_HANDLE_POSITION_CURSOR, |
613 | 645 | GTK_TEXT_HANDLE_POSITION_SELECTION_START); |
| 646 | handle_window = &priv->windows[pos]; |
614 | 647 | |
615 | 648 | if (!priv->realized) |
616 | 649 | return; |
… |
… |
_gtk_text_handle_set_position (GtkTextHandle *handle, |
620 | 653 | pos != GTK_TEXT_HANDLE_POSITION_CURSOR)) |
621 | 654 | return; |
622 | 655 | |
| 656 | handle_window->pointing_to = *rect; |
| 657 | handle_window->has_point = TRUE; |
623 | 658 | gdk_window_get_root_coords (priv->relative_to, |
624 | 659 | rect->x, rect->y, |
625 | | &x, &y); |
626 | | _gtk_text_handle_get_size (handle, &width, &height); |
627 | | handle_window = &priv->windows[pos]; |
628 | | |
629 | | if (pos == GTK_TEXT_HANDLE_POSITION_CURSOR) |
630 | | y += rect->height; |
631 | | else |
632 | | y -= height; |
| 660 | &handle_window->pointing_to.x, |
| 661 | &handle_window->pointing_to.y); |
633 | 662 | |
634 | | x -= width / 2; |
635 | | |
636 | | gdk_window_move (handle_window->window, x, y); |
637 | | handle_window->pointing_to = *rect; |
| 663 | _gtk_text_handle_update_window_state (handle, pos); |
638 | 664 | } |
639 | 665 | |
640 | 666 | void |
… |
… |
_gtk_text_handle_set_visible (GtkTextHandle *handle, |
659 | 685 | if (!window) |
660 | 686 | return; |
661 | 687 | |
662 | | if (!visible) |
663 | | gdk_window_hide (window); |
664 | | else |
665 | | { |
666 | | if (priv->mode == GTK_TEXT_HANDLE_MODE_NONE || |
667 | | (priv->mode == GTK_TEXT_HANDLE_MODE_CURSOR && |
668 | | pos != GTK_TEXT_HANDLE_POSITION_CURSOR)) |
669 | | return; |
670 | | |
671 | | if (!gdk_window_is_visible (window)) |
672 | | gdk_window_show (window); |
673 | | } |
| 688 | priv->windows[pos].user_visible = visible; |
| 689 | _gtk_text_handle_update_window_state (handle, pos); |
674 | 690 | } |
675 | 691 | |
676 | 692 | gboolean |