aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJan Djärv2003-03-17 23:03:53 +0000
committerJan Djärv2003-03-17 23:03:53 +0000
commit17097258bdba66a449f6c690090a2b536c80b17b (patch)
tree52319a9267c01a419d7d0dc0302afc4fa913afea /src
parent8cb9dfbfc56c4ca8dcd9adef11bbc8d949387936 (diff)
downloademacs-17097258bdba66a449f6c690090a2b536c80b17b.tar.gz
emacs-17097258bdba66a449f6c690090a2b536c80b17b.zip
New approach to scrolling and scroll bars for better redraw and smoother
scroll bar behaviour.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog24
-rw-r--r--src/gtkutil.c243
-rw-r--r--src/xterm.c7
3 files changed, 169 insertions, 105 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 4c9d573c74e..cd271f1b116 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,27 @@
12003-03-18 Jan Dj,Ad(Brv <jan.h.d@swipnet.se>
2
3 * xterm.c (xg_scroll_callback): Remove xg_ignore_next_thumb.
4
5 * gtkutil.c (xg_initialize): Remove xg_ignore_next_thumb.
6
72003-03-17 Jan Dj,Ad(Brv <jan.h.d@swipnet.se>
8
9 * gtkutil.c: Removed handle_fixed_child, struct xg_last_sb_pos.
10 (xg_resize_widgets): Don't call foreach(handle_fixed_child).
11 (xg_gtk_scroll_destroy): Remove free of struct xg_last_sb_pos.
12 (scroll_bar_button_cb): Set bar->dragging to NIL on button release.
13 (xg_create_scroll_bar): Pass bar to button event callback.
14 (xg_find_top_left_in_fixed): New function.
15 (xg_update_scrollbar_pos): Don't call gdk_window_clear on
16 whole scroll bar area. Get old position with
17 xg_find_top_left_in_fixed, calculate and only clear needed areas.
18 (xg_set_toolkit_scroll_bar_thumb): Do not adjust scroll bar if
19 dragging is in progress. Calculate whole as for Motif.
20 Remove code that saved last values. Call gtk_range functions to
21 set scroll bar sizes.
22
23 * gtkutil.h: Removed xg_ignore_next_thumb.
24
12003-03-17 Juanma Barranquero <lektu@terra.es> 252003-03-17 Juanma Barranquero <lektu@terra.es>
2 26
3 * makefile.w32-in ($(BLD)/xdisp.$(O)): Add dependency on blockinput.h 27 * makefile.w32-in ($(BLD)/xdisp.$(O)): Add dependency on blockinput.h
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 0b8f9294612..d66b8523b18 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -37,17 +37,6 @@ Boston, MA 02111-1307, USA. */
37 (PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f)) 37 (PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
38 38
39 39
40/* Key to save a struct xg_last_sb_pos in the scroll bars. */
41#define XG_LAST_SB_POS "emacs_last_sb_pos"
42
43
44/* Use this in scroll bars to keep track of when redraw is really needed. */
45struct xg_last_sb_pos
46{
47 int portion, position, whole;
48};
49
50
51 40
52/*********************************************************************** 41/***********************************************************************
53 Utility functions 42 Utility functions
@@ -298,24 +287,6 @@ xg_resize_outer_widget (f, columns, rows)
298 gdk_window_process_all_updates (); 287 gdk_window_process_all_updates ();
299} 288}
300 289
301/* When the Emacs frame is resized, we must call this function for each
302 child of our GtkFixed widget. The children are scroll bars and
303 we invalidate the last position data here so it will be properly
304 redrawn later when xg_update_scrollbar_pos is called.
305 W is the child widget.
306 CLIENT_DATA is not used. */
307static handle_fixed_child (w, client_data)
308 GtkWidget *w;
309 gpointer client_data;
310{
311 struct xg_last_sb_pos *last_pos
312 = g_object_get_data (G_OBJECT (w), XG_LAST_SB_POS);
313 if (last_pos)
314 {
315 last_pos->portion = last_pos->position = last_pos->whole = .1;
316 }
317}
318
319/* This gets called after the frame F has been cleared. Since that is 290/* This gets called after the frame F has been cleared. Since that is
320 done with X calls, we need to redraw GTK widget (scroll bars). */ 291 done with X calls, we need to redraw GTK widget (scroll bars). */
321void 292void
@@ -326,9 +297,6 @@ xg_frame_cleared (f)
326 297
327 if (wfixed) 298 if (wfixed)
328 { 299 {
329 gtk_container_foreach (GTK_CONTAINER (wfixed),
330 (GtkCallback) handle_fixed_child,
331 NULL);
332 gtk_container_set_reallocate_redraws (GTK_CONTAINER (wfixed), TRUE); 300 gtk_container_set_reallocate_redraws (GTK_CONTAINER (wfixed), TRUE);
333 gdk_window_process_all_updates (); 301 gdk_window_process_all_updates ();
334 } 302 }
@@ -2277,11 +2245,6 @@ free_frame_menubar (f)
2277 to indicate that callback should do nothing. */ 2245 to indicate that callback should do nothing. */
2278int xg_ignore_gtk_scrollbar; 2246int xg_ignore_gtk_scrollbar;
2279 2247
2280/* After we send a scroll bar event, x_set_toolkit_scroll_bar_thumb will
2281 be called. For some reason that needs to be debugged, it gets called
2282 with bad values. Thus, we set this variable to ignore those calls. */
2283int xg_ignore_next_thumb;
2284
2285/* SET_SCROLL_BAR_X_WINDOW assumes the second argument fits in 2248/* SET_SCROLL_BAR_X_WINDOW assumes the second argument fits in
2286 32 bits. But we want to store pointers, and they may be larger 2249 32 bits. But we want to store pointers, and they may be larger
2287 than 32 bits. Keep a mapping from integer index to widget pointers 2250 than 32 bits. Keep a mapping from integer index to widget pointers
@@ -2391,16 +2354,15 @@ xg_gtk_scroll_destroy (widget, data)
2391 2354
2392 p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA); 2355 p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
2393 if (p) xfree (p); 2356 if (p) xfree (p);
2394 p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_POS);
2395 if (p) xfree (p);
2396 xg_remove_widget_from_map (id); 2357 xg_remove_widget_from_map (id);
2397} 2358}
2398 2359
2399/* Callback for button press/release events. Used to start timer so that 2360/* Callback for button press/release events. Used to start timer so that
2400 the scroll bar repetition timer in GTK gets handeled. 2361 the scroll bar repetition timer in GTK gets handeled.
2362 Also, sets bar->dragging to Qnil when dragging (button release) is done.
2401 WIDGET is the scroll bar widget the event is for (not used). 2363 WIDGET is the scroll bar widget the event is for (not used).
2402 EVENT contains the event. 2364 EVENT contains the event.
2403 USER_DATA is 0 (not used). 2365 USER_DATA points to the struct scrollbar structure.
2404 2366
2405 Returns FALSE to tell GTK that it shall continue propagate the event 2367 Returns FALSE to tell GTK that it shall continue propagate the event
2406 to widgets. */ 2368 to widgets. */
@@ -2412,9 +2374,13 @@ scroll_bar_button_cb (widget, event, user_data)
2412{ 2374{
2413 if (event->type == GDK_BUTTON_PRESS && ! xg_timer) 2375 if (event->type == GDK_BUTTON_PRESS && ! xg_timer)
2414 xg_start_timer (); 2376 xg_start_timer ();
2415 else if (event->type == GDK_BUTTON_RELEASE && xg_timer) 2377 else if (event->type == GDK_BUTTON_RELEASE)
2416 xg_stop_timer (); 2378 {
2417 2379 struct scroll_bar *bar = (struct scroll_bar *) user_data;
2380 if (xg_timer) xg_stop_timer ();
2381 bar->dragging = Qnil;
2382 }
2383
2418 return FALSE; 2384 return FALSE;
2419} 2385}
2420 2386
@@ -2460,28 +2426,18 @@ xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name)
2460 g_signal_connect (G_OBJECT (wscroll), 2426 g_signal_connect (G_OBJECT (wscroll),
2461 "button-press-event", 2427 "button-press-event",
2462 G_CALLBACK (scroll_bar_button_cb), 2428 G_CALLBACK (scroll_bar_button_cb),
2463 0); 2429 (gpointer)bar);
2464 g_signal_connect (G_OBJECT (wscroll), 2430 g_signal_connect (G_OBJECT (wscroll),
2465 "button-release-event", 2431 "button-release-event",
2466 G_CALLBACK (scroll_bar_button_cb), 2432 G_CALLBACK (scroll_bar_button_cb),
2467 0); 2433 (gpointer)bar);
2468 2434
2469 gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), 2435 gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget),
2470 wscroll, 0, 0); 2436 wscroll, -1, -1);
2471 2437
2472 /* Set the cursor to an arrow. */ 2438 /* Set the cursor to an arrow. */
2473 xg_set_cursor (wscroll, &xg_left_ptr_cursor); 2439 xg_set_cursor (wscroll, &xg_left_ptr_cursor);
2474 2440
2475 /* Allocate a place to hold the last scollbar size. GTK redraw for
2476 scroll bars is basically clear all, and then redraw. This flickers
2477 a lot since xg_update_scrollbar_pos gets called on every cursor move
2478 and a lot more places. So we have this to check if a redraw really
2479 is needed. */
2480 struct xg_last_sb_pos *last_pos
2481 = (struct xg_last_sb_pos *) xmalloc (sizeof (struct xg_last_sb_pos));
2482 last_pos->portion = last_pos->position = last_pos->whole = -1;
2483 g_object_set_data (G_OBJECT (wscroll), XG_LAST_SB_POS, last_pos);
2484
2485 SET_SCROLL_BAR_X_WINDOW (bar, scroll_id); 2441 SET_SCROLL_BAR_X_WINDOW (bar, scroll_id);
2486} 2442}
2487 2443
@@ -2509,6 +2465,29 @@ xg_remove_scroll_bar (f, scrollbar_id)
2509 } 2465 }
2510} 2466}
2511 2467
2468/* Find left/top for widget W in GtkFixed widget WFIXED. */
2469static void
2470xg_find_top_left_in_fixed (w, wfixed, left, top)
2471 GtkWidget *w, *wfixed;
2472 int *left, *top;
2473{
2474 GList *iter;
2475
2476 for (iter = GTK_FIXED (wfixed)->children; iter; iter = g_list_next (iter))
2477 {
2478 GtkFixedChild *child = (GtkFixedChild *) iter->data;
2479
2480 if (child->widget == w)
2481 {
2482 *left = child->x;
2483 *top = child->y;
2484 return;
2485 }
2486 }
2487
2488 /* Shall never end up here. */
2489 abort ();
2490}
2512 2491
2513/* Update the position of the vertical scroll bar represented by SCROLLBAR_ID 2492/* Update the position of the vertical scroll bar represented by SCROLLBAR_ID
2514 in frame F. 2493 in frame F.
@@ -2525,34 +2504,101 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
2525{ 2504{
2526 2505
2527 GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id); 2506 GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id);
2528 2507
2529 if (wscroll) 2508 if (wscroll)
2530 { 2509 {
2531 int gheight = max (height, 1);
2532 struct xg_last_sb_pos *last_pos
2533 = g_object_get_data (G_OBJECT (wscroll), XG_LAST_SB_POS);
2534 GtkWidget *wfixed = f->output_data.x->edit_widget; 2510 GtkWidget *wfixed = f->output_data.x->edit_widget;
2511 int gheight = max (height, 1);
2512 int canon_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
2513 int winextra = canon_width > width ? (canon_width - width) / 2 : 0;
2514 int bottom = top + gheight;
2535 2515
2536 last_pos->portion = last_pos->position = last_pos->whole = -1; 2516 gint slider_width;
2537 xg_ignore_next_thumb = 0; 2517 int oldtop, oldleft, oldbottom;
2518 GtkRequisition req;
2519
2520 /* Get old values. */
2521 xg_find_top_left_in_fixed (wscroll, wfixed, &oldleft, &oldtop);
2522 gtk_widget_size_request (wscroll, &req);
2523 oldbottom = oldtop + req.height;
2524
2525 /* Scroll bars in GTK has a fixed width, so if we say width 16, it
2526 will only be its fixed width (14 is default) anyway, the rest is
2527 blank. We are drawing the mode line across scroll bars when
2528 the frame is split:
2529 |bar| |fringe|
2530 ----------------
2531 mode line
2532 ----------------
2533 |bar| |fringe|
2534
2535 When we "unsplit" the frame:
2536
2537 |bar| |fringe|
2538 -| |-| |
2539 m¦ |i| |
2540 -| |-| |
2541 | | | |
2542
2543
2544 the remains of the mode line can be seen in these blank spaces.
2545 So we must clear them explicitly.
2546 GTK scroll bars should do that, but they don't.
2547 Also, the scroll bar canonical width may be wider than the width
2548 passed in here. */
2549
2550 if (oldtop != -1 && oldleft != -1)
2551 {
2552 int gtkextra;
2553 int xl, xr, wblank;
2554 int bottomdiff, topdiff;
2555
2556 gtk_widget_style_get (wscroll, "slider_width", &slider_width, NULL);
2557 gtkextra = width > slider_width ? (width - slider_width) / 2 : 0;
2558
2559 xl = left - winextra;
2560 wblank = gtkextra + winextra;
2561 xr = left + gtkextra + slider_width;
2562 bottomdiff = abs (oldbottom - bottom);
2563 topdiff = abs (oldtop - top);
2564
2565 if (oldtop > top)
2566 {
2567 gdk_window_clear_area (wfixed->window, xl, top, wblank, topdiff);
2568 gdk_window_clear_area (wfixed->window, xr, top, wblank, topdiff);
2569 }
2570 else if (oldtop < top)
2571 {
2572 gdk_window_clear_area (wfixed->window, xl, oldtop, wblank,
2573 topdiff);
2574 gdk_window_clear_area (wfixed->window, xr, oldtop, wblank,
2575 topdiff);
2576 }
2577
2578 if (oldbottom > bottom)
2579 {
2580 gdk_window_clear_area (wfixed->window, xl, bottom, wblank,
2581 bottomdiff);
2582 gdk_window_clear_area (wfixed->window, xr, bottom, wblank,
2583 bottomdiff);
2584 }
2585 else if (oldbottom < bottom)
2586 {
2587 gdk_window_clear_area (wfixed->window, xl, oldbottom, wblank,
2588 bottomdiff);
2589 gdk_window_clear_area (wfixed->window, xr, oldbottom, wblank,
2590 bottomdiff);
2591 }
2592 }
2538 2593
2594 /* Move and resize to new values. */
2539 gtk_fixed_move (GTK_FIXED (wfixed), wscroll, left, top); 2595 gtk_fixed_move (GTK_FIXED (wfixed), wscroll, left, top);
2540 gtk_widget_set_size_request (wscroll, width, gheight); 2596 gtk_widget_set_size_request (wscroll, width, gheight);
2541 2597
2542 gtk_container_set_reallocate_redraws (GTK_CONTAINER (wfixed), TRUE); 2598 gtk_container_set_reallocate_redraws (GTK_CONTAINER (wfixed), TRUE);
2543 2599
2544 /* Must force out update so wscroll gets the resize. 2600 /* Make GTK draw the new sizes. We are not using a pure GTK event
2545 Otherwise, the gdk_window_clear clears the old window size. */ 2601 loop so we need to do this. */
2546 gdk_window_process_all_updates ();
2547
2548 /* The scroll bar doesn't explicitly redraw the whole window
2549 when a resize occurs. Since the scroll bar seems to be fixed
2550 in width it doesn't fill the space reserved, so we must clear
2551 the whole window. */
2552 gdk_window_clear (wscroll->window);
2553
2554 /* Since we are not using a pure gtk event loop, we must force out
2555 pending update events with this call. */
2556 gdk_window_process_all_updates (); 2602 gdk_window_process_all_updates ();
2557 2603
2558 SET_FRAME_GARBAGED (f); 2604 SET_FRAME_GARBAGED (f);
@@ -2570,16 +2616,10 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
2570 GtkWidget *wscroll = xg_get_widget_from_map (SCROLL_BAR_X_WINDOW (bar)); 2616 GtkWidget *wscroll = xg_get_widget_from_map (SCROLL_BAR_X_WINDOW (bar));
2571 2617
2572 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); 2618 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2573 struct xg_last_sb_pos *last_pos
2574 = (wscroll ? g_object_get_data (G_OBJECT (wscroll), XG_LAST_SB_POS) : 0);
2575 2619
2576 BLOCK_INPUT; 2620 BLOCK_INPUT;
2577 if (wscroll 2621
2578 && ! xg_ignore_next_thumb 2622 if (wscroll && NILP (bar->dragging))
2579 && last_pos
2580 && (last_pos->portion != portion
2581 || last_pos->position != position
2582 || last_pos->whole != whole))
2583 { 2623 {
2584 GtkAdjustment *adj; 2624 GtkAdjustment *adj;
2585 gdouble shown; 2625 gdouble shown;
@@ -2588,6 +2628,14 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
2588 2628
2589 adj = gtk_range_get_adjustment (GTK_RANGE (wscroll)); 2629 adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
2590 2630
2631 /* We do the same as for MOTIF in xterm.c, assume 30 chars per line
2632 rather than the real portion value. This makes the thumb less likely
2633 to resize and that looks better. */
2634 portion = XFASTINT (XWINDOW (bar->window)->height) * 30;
2635 /* When the thumb is at the bottom, position == whole.
2636 So we need to increase `whole' to make space for the thumb. */
2637 whole += portion;
2638
2591 if (whole <= 0) 2639 if (whole <= 0)
2592 top = 0, shown = 1; 2640 top = 0, shown = 1;
2593 else 2641 else
@@ -2604,34 +2652,28 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
2604 value = min (value, whole - size); 2652 value = min (value, whole - size);
2605 value = max (value, XG_SB_MIN); 2653 value = max (value, XG_SB_MIN);
2606 2654
2607 adj->upper = max (whole, size);
2608 adj->page_size = (int)size; 2655 adj->page_size = (int)size;
2609 2656
2610 /* Assume a page increment is about 95% of the page size */
2611 adj->page_increment = (int) (0.95*adj->page_size);
2612
2613 /* Assume all lines are equal. */
2614 adj->step_increment = portion / max (1, FRAME_HEIGHT (f));
2615
2616 if (last_pos)
2617 {
2618 last_pos->portion = portion;
2619 last_pos->position = position;
2620 last_pos->whole = whole;
2621 }
2622
2623 /* gtk_range_set_value invokes the callback. Set 2657 /* gtk_range_set_value invokes the callback. Set
2624 ignore_gtk_scrollbar to make the callback do nothing */ 2658 ignore_gtk_scrollbar to make the callback do nothing */
2625 xg_ignore_gtk_scrollbar = 1; 2659 xg_ignore_gtk_scrollbar = 1;
2660
2661 gtk_range_set_range (GTK_RANGE (wscroll), adj->lower, max (whole, size));
2662
2663 /* Assume all lines are of equal size. */
2664 /* Assume a page increment is about 95% of the page size */
2665 gtk_range_set_increments (GTK_RANGE (wscroll),
2666 portion / max (1, FRAME_HEIGHT (f)),
2667 (int) (0.95*adj->page_size));
2668
2626 gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value); 2669 gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
2627 xg_ignore_gtk_scrollbar = 0; 2670 xg_ignore_gtk_scrollbar = 0;
2628 2671
2629 /* Make sure the scroll bar is redrawn with new thumb */ 2672 /* Make GTK draw the new thumb. We are not using a pure GTK event
2630 gtk_widget_queue_draw (wscroll); 2673 loop so we need to do this. */
2674 gdk_window_process_all_updates ();
2631 } 2675 }
2632 2676
2633 gdk_window_process_all_updates ();
2634 xg_ignore_next_thumb = 0;
2635 UNBLOCK_INPUT; 2677 UNBLOCK_INPUT;
2636} 2678}
2637 2679
@@ -3079,7 +3121,6 @@ void
3079xg_initialize () 3121xg_initialize ()
3080{ 3122{
3081 xg_ignore_gtk_scrollbar = 0; 3123 xg_ignore_gtk_scrollbar = 0;
3082 xg_ignore_next_thumb = 0;
3083 xg_left_ptr_cursor = 0; 3124 xg_left_ptr_cursor = 0;
3084 xg_did_tearoff = 0; 3125 xg_did_tearoff = 0;
3085 3126
diff --git a/src/xterm.c b/src/xterm.c
index 380e4c73d7c..3aac2aeaf67 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -6395,7 +6395,7 @@ xm_scroll_callback (widget, client_data, call_data)
6395 6395
6396#else /* !USE_MOTIF, i.e. Xaw or GTK */ 6396#else /* !USE_MOTIF, i.e. Xaw or GTK */
6397#ifdef USE_GTK 6397#ifdef USE_GTK
6398/* Scroll bar callback for Gtk scroll bars. WIDGET is the scroll 6398/* Scroll bar callback for GTK scroll bars. WIDGET is the scroll
6399 bar adjustment widget. DATA is a pointer to the scroll_bar structure. */ 6399 bar adjustment widget. DATA is a pointer to the scroll_bar structure. */
6400 6400
6401static void 6401static void
@@ -6453,13 +6453,12 @@ xg_scroll_callback (widget, data)
6453 { 6453 {
6454 part = scroll_bar_handle; 6454 part = scroll_bar_handle;
6455 whole = adj->upper - adj->page_size; 6455 whole = adj->upper - adj->page_size;
6456 portion = min (position, whole); 6456 portion = min ((int)position, whole);
6457 bar->dragging = make_number (portion); 6457 bar->dragging = make_number ((int)portion);
6458 } 6458 }
6459 6459
6460 if (part >= 0) 6460 if (part >= 0)
6461 { 6461 {
6462 xg_ignore_next_thumb = 1;
6463 window_being_scrolled = bar->window; 6462 window_being_scrolled = bar->window;
6464 last_scroll_bar_part = part; 6463 last_scroll_bar_part = part;
6465 x_send_scroll_bar_event (bar->window, part, portion, whole); 6464 x_send_scroll_bar_event (bar->window, part, portion, whole);