]> code.delx.au - gnu-emacs/blobdiff - src/gtkutil.c
* macterm.c: Remove consolidated defines and code.
[gnu-emacs] / src / gtkutil.c
index 7c08ca77c7730603ad224e4c83c0b0b1b42b4629..61e797493541e724009bf9f569b1f29efba9494b 100644 (file)
@@ -35,6 +35,8 @@ Boston, MA 02111-1307, USA.  */
 
 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
   (PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
 
 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
   (PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
+
+
 \f
 /***********************************************************************
                       Utility functions
 \f
 /***********************************************************************
                       Utility functions
@@ -285,6 +287,24 @@ xg_resize_outer_widget (f, columns, rows)
   gdk_window_process_all_updates ();
 }
 
   gdk_window_process_all_updates ();
 }
 
+/* This gets called after the frame F has been cleared.  Since that is
+   done with X calls, we need to redraw GTK widget (scroll bars).  */
+void
+xg_frame_cleared (f)
+     FRAME_PTR f;
+{
+  GtkWidget *w = f->output_data.x->widget;
+
+  if (w)
+    {
+      gtk_container_set_reallocate_redraws (GTK_CONTAINER (w), TRUE);
+      gtk_container_foreach (GTK_CONTAINER (w),
+                             (GtkCallback) gtk_widget_queue_draw,
+                             0);
+      gdk_window_process_all_updates ();
+    }
+}
+
 /* Function to handle resize of our widgets.  Since Emacs has some layouts
    that does not fit well with GTK standard containers, we do most layout
    manually.
 /* Function to handle resize of our widgets.  Since Emacs has some layouts
    that does not fit well with GTK standard containers, we do most layout
    manually.
@@ -314,7 +334,8 @@ xg_resize_widgets (f, pixelwidth, pixelheight)
       all.height = pixelheight - mbheight - tbheight;
 
       gtk_widget_size_allocate (x->edit_widget, &all);
       all.height = pixelheight - mbheight - tbheight;
 
       gtk_widget_size_allocate (x->edit_widget, &all);
-      gdk_window_process_all_updates ();
+
+      xg_frame_cleared (f);
 
       change_frame_size (f, rows, columns, 0, 1, 0);
       SET_FRAME_GARBAGED (f);
 
       change_frame_size (f, rows, columns, 0, 1, 0);
       SET_FRAME_GARBAGED (f);
@@ -1344,6 +1365,10 @@ xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group)
   return w;
 }
 
   return w;
 }
 
+static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback,
+                                   GCallback, GCallback, int, int, int,
+                                   GtkWidget *, xg_menu_cb_data *, char *));
+
 /* Create a full menu tree specified by DATA.
    F is the frame the created menu belongs to.
    SELECT_CB is the callback to use when a menu item is selected.
 /* Create a full menu tree specified by DATA.
    F is the frame the created menu belongs to.
    SELECT_CB is the callback to use when a menu item is selected.
@@ -2180,6 +2205,8 @@ xg_update_frame_menubar (f)
 
   SET_FRAME_GARBAGED (f);
   UNBLOCK_INPUT;
 
   SET_FRAME_GARBAGED (f);
   UNBLOCK_INPUT;
+
+  return 1;
 }
 
 /* Get rid of the menu bar of frame F, and free its storage.
 }
 
 /* Get rid of the menu bar of frame F, and free its storage.
@@ -2221,11 +2248,6 @@ free_frame_menubar (f)
    to indicate that callback should do nothing.  */
 int xg_ignore_gtk_scrollbar;
 
    to indicate that callback should do nothing.  */
 int xg_ignore_gtk_scrollbar;
 
-/* After we send a scroll bar event,  x_set_toolkit_scroll_bar_thumb will
-   be called.  For some reason that needs to be debugged, it gets called
-   with bad values.  Thus, we set this variable to ignore those calls.  */
-int xg_ignore_next_thumb;
-
 /* SET_SCROLL_BAR_X_WINDOW assumes the second argument fits in
    32 bits.  But we want to store pointers, and they may be larger
    than 32 bits.  Keep a mapping from integer index to widget pointers
 /* SET_SCROLL_BAR_X_WINDOW assumes the second argument fits in
    32 bits.  But we want to store pointers, and they may be larger
    than 32 bits.  Keep a mapping from integer index to widget pointers
@@ -2324,7 +2346,7 @@ xg_get_scroll_id_for_window (wid)
 
 /* Callback invoked when scroll bar WIDGET is destroyed.
    DATA is the index into id_to_widget for WIDGET.
 
 /* Callback invoked when scroll bar WIDGET is destroyed.
    DATA is the index into id_to_widget for WIDGET.
-   We free pointer to last scroll bar value here and remove the index.  */
+   We free pointer to last scroll bar values here and remove the index.  */
 static void
 xg_gtk_scroll_destroy (widget, data)
      GtkWidget *widget;
 static void
 xg_gtk_scroll_destroy (widget, data)
      GtkWidget *widget;
@@ -2340,9 +2362,10 @@ xg_gtk_scroll_destroy (widget, data)
 
 /* Callback for button press/release events.  Used to start timer so that
    the scroll bar repetition timer in GTK gets handeled.
 
 /* Callback for button press/release events.  Used to start timer so that
    the scroll bar repetition timer in GTK gets handeled.
+   Also, sets bar->dragging to Qnil when dragging (button release) is done.
    WIDGET is the scroll bar widget the event is for (not used).
    EVENT contains the event.
    WIDGET is the scroll bar widget the event is for (not used).
    EVENT contains the event.
-   USER_DATA is 0 (not used).
+   USER_DATA points to the struct scrollbar structure.
 
    Returns FALSE to tell GTK that it shall continue propagate the event
    to widgets.  */
 
    Returns FALSE to tell GTK that it shall continue propagate the event
    to widgets.  */
@@ -2354,9 +2377,13 @@ scroll_bar_button_cb (widget, event, user_data)
 {
   if (event->type == GDK_BUTTON_PRESS && ! xg_timer)
     xg_start_timer ();
 {
   if (event->type == GDK_BUTTON_PRESS && ! xg_timer)
     xg_start_timer ();
-  else if (event->type == GDK_BUTTON_RELEASE && xg_timer)
-    xg_stop_timer ();
-
+  else if (event->type == GDK_BUTTON_RELEASE)
+    {
+      struct scroll_bar *bar = (struct scroll_bar *) user_data;
+      if (xg_timer) xg_stop_timer ();
+      bar->dragging = Qnil;
+    }
+  
   return FALSE;
 }
 
   return FALSE;
 }
 
@@ -2402,14 +2429,14 @@ xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name)
   g_signal_connect (G_OBJECT (wscroll),
                     "button-press-event",
                     G_CALLBACK (scroll_bar_button_cb),
   g_signal_connect (G_OBJECT (wscroll),
                     "button-press-event",
                     G_CALLBACK (scroll_bar_button_cb),
-                    0);
+                    (gpointer)bar);
   g_signal_connect (G_OBJECT (wscroll),
                     "button-release-event",
                     G_CALLBACK (scroll_bar_button_cb),
   g_signal_connect (G_OBJECT (wscroll),
                     "button-release-event",
                     G_CALLBACK (scroll_bar_button_cb),
-                    0);
+                    (gpointer)bar);
 
   gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget),
 
   gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget),
-                 wscroll, 0, 0);
+                 wscroll, -1, -1);
 
   /* Set the cursor to an arrow.  */
   xg_set_cursor (wscroll, &xg_left_ptr_cursor);
 
   /* Set the cursor to an arrow.  */
   xg_set_cursor (wscroll, &xg_left_ptr_cursor);
@@ -2441,6 +2468,29 @@ xg_remove_scroll_bar (f, scrollbar_id)
     }
 }
 
     }
 }
 
+/* Find left/top for widget W in GtkFixed widget WFIXED.  */
+static void
+xg_find_top_left_in_fixed (w, wfixed, left, top)
+     GtkWidget *w, *wfixed;
+     int *left, *top;
+{
+  GList *iter;
+
+  for (iter = GTK_FIXED (wfixed)->children; iter; iter = g_list_next (iter))
+    {
+      GtkFixedChild *child = (GtkFixedChild *) iter->data;
+
+      if (child->widget == w)
+        {
+          *left = child->x;
+          *top = child->y;
+          return;
+        }
+    }
+
+  /* Shall never end up here.  */
+  abort ();
+}
 
 /* Update the position of the vertical scroll bar represented by SCROLLBAR_ID
    in frame F.
 
 /* Update the position of the vertical scroll bar represented by SCROLLBAR_ID
    in frame F.
@@ -2457,28 +2507,101 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
 {
 
   GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id);
 {
 
   GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id);
-
+  
   if (wscroll)
     {
   if (wscroll)
     {
+      GtkWidget *wfixed = f->output_data.x->edit_widget;
       int gheight = max (height, 1);
       int gheight = max (height, 1);
+      int canon_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
+      int winextra = canon_width > width ? (canon_width - width) / 2 : 0;
+      int bottom = top + gheight;
 
 
-      gtk_fixed_move (GTK_FIXED (f->output_data.x->edit_widget),
-                      wscroll, left, top);
+      gint slider_width;
+      int oldtop, oldleft, oldbottom;
+      GtkRequisition req;
+      
+      /* Get old values.  */
+      xg_find_top_left_in_fixed (wscroll, wfixed, &oldleft, &oldtop);
+      gtk_widget_size_request (wscroll, &req);
+      oldbottom = oldtop + req.height;
+
+      /* Scroll bars in GTK has a fixed width, so if we say width 16, it
+         will only be its fixed width (14 is default) anyway, the rest is
+         blank.  We are drawing the mode line across scroll bars when
+         the frame is split:
+                               |bar| |fringe|
+                              ----------------
+                              mode line
+                              ----------------
+                               |bar| |fringe|
+
+         When we "unsplit" the frame:
+
+                               |bar| |fringe|
+                              -|   |-|      |
+                              m¦   |i|      |
+                              -|   |-|      |
+                               |   | |      |
+
+
+         the remains of the mode line can be seen in these blank spaces.
+         So we must clear them explicitly.
+         GTK scroll bars should do that, but they don't.
+         Also, the scroll bar canonical width may be wider than the width
+         passed in here.  */
+
+      if (oldtop != -1 && oldleft != -1)
+        {
+          int gtkextra;
+          int xl, xr, wblank;
+          int bottomdiff, topdiff;
+
+          gtk_widget_style_get (wscroll, "slider_width", &slider_width, NULL);
+          gtkextra = width > slider_width ? (width - slider_width) / 2 : 0;
+        
+          xl = left - winextra;
+          wblank = gtkextra + winextra;
+          xr = left + gtkextra + slider_width;
+          bottomdiff = abs (oldbottom - bottom);
+          topdiff = abs (oldtop - top);
+
+          if (oldtop > top)
+            {
+              gdk_window_clear_area (wfixed->window, xl, top, wblank, topdiff);
+              gdk_window_clear_area (wfixed->window, xr, top, wblank, topdiff);
+            }
+          else if (oldtop < top)
+            {
+              gdk_window_clear_area (wfixed->window, xl, oldtop, wblank,
+                                     topdiff);
+              gdk_window_clear_area (wfixed->window, xr, oldtop, wblank,
+                                     topdiff);
+            }
 
 
-      gtk_widget_set_size_request (wscroll, width, gheight);
+          if (oldbottom > bottom)
+            {
+              gdk_window_clear_area (wfixed->window, xl, bottom, wblank,
+                                     bottomdiff);
+              gdk_window_clear_area (wfixed->window, xr, bottom, wblank,
+                                     bottomdiff);
+            }
+          else if (oldbottom < bottom)
+            {
+              gdk_window_clear_area (wfixed->window, xl, oldbottom, wblank,
+                                     bottomdiff);
+              gdk_window_clear_area (wfixed->window, xr, oldbottom, wblank,
+                                     bottomdiff);
+            }
+        }
 
 
-      /* Must force out update so wscroll gets the resize.
-         Otherwise, the gdk_window_clear clears the old window size.  */
-      gdk_window_process_all_updates ();
+      /* Move and resize to new values.  */
+      gtk_fixed_move (GTK_FIXED (wfixed), wscroll, left, top);
+      gtk_widget_set_size_request (wscroll, width, gheight);
 
 
-      /* The scroll bar doesn't explicitly redraw the whole window
-         when a resize occurs.  Since the scroll bar seems to be fixed
-         in width it doesn't fill the space reserved, so we must clear
-         the whole window.  */
-      gdk_window_clear (wscroll->window);
+      gtk_container_set_reallocate_redraws (GTK_CONTAINER (wfixed), TRUE);
 
 
-      /* Since we are not using a pure gtk event loop, we must force out
-         pending update events with this call.  */
+      /* Make GTK draw the new sizes.  We are not using a pure GTK event
+         loop so we need to do this.  */
       gdk_window_process_all_updates ();
 
       SET_FRAME_GARBAGED (f);
       gdk_window_process_all_updates ();
 
       SET_FRAME_GARBAGED (f);
@@ -2498,15 +2621,25 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
   FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
 
   BLOCK_INPUT;
   FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
 
   BLOCK_INPUT;
-  if (wscroll && ! xg_ignore_next_thumb)
+
+  if (wscroll && NILP (bar->dragging))
     {
       GtkAdjustment *adj;
       gdouble shown;
       gdouble top;
       int size, value;
     {
       GtkAdjustment *adj;
       gdouble shown;
       gdouble top;
       int size, value;
+      int new_upper, new_step;
 
       adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
 
 
       adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
 
+      /* We do the same as for MOTIF in xterm.c, assume 30 chars per line
+         rather than the real portion value.  This makes the thumb less likely
+         to resize and that looks better.  */
+      portion = XFASTINT (XWINDOW (bar->window)->height) * 30;
+      /* When the thumb is at the bottom, position == whole.
+         So we need to increase `whole' to make space for the thumb.  */
+      whole += portion;
+
       if (whole <= 0)
         top = 0, shown = 1;
       else
       if (whole <= 0)
         top = 0, shown = 1;
       else
@@ -2523,26 +2656,40 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
       value = min (value, whole - size);
       value = max (value, XG_SB_MIN);
 
       value = min (value, whole - size);
       value = max (value, XG_SB_MIN);
 
-      adj->upper = max (whole, size);
-      adj->page_size = (int)size;
-
-      /* Assume a page increment is about 95% of the page size  */
-      adj->page_increment = (int) (0.95*adj->page_size);
-
-      /* Assume all lines are equal.  */
-      adj->step_increment = portion / max (1, FRAME_HEIGHT (f));
-
       /* gtk_range_set_value invokes the callback.  Set
          ignore_gtk_scrollbar to make the callback do nothing  */
       xg_ignore_gtk_scrollbar = 1;
       /* gtk_range_set_value invokes the callback.  Set
          ignore_gtk_scrollbar to make the callback do nothing  */
       xg_ignore_gtk_scrollbar = 1;
-      gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
+
+      new_upper = max (whole, size);
+      new_step  =  portion / max (1, FRAME_HEIGHT (f));
+
+      if ((int) adj->page_size != size
+          || (int) adj->upper != new_upper
+          || (int) adj->step_increment != new_step)
+        {
+          adj->page_size = (int) size;
+
+          gtk_range_set_range (GTK_RANGE (wscroll), adj->lower,
+                               (gdouble) new_upper);
+
+          /* Assume all lines are of equal size.  */
+          /* Assume a page increment is about 95% of the page size  */
+          gtk_range_set_increments (GTK_RANGE (wscroll),
+                                    portion / max (1, FRAME_HEIGHT (f)),
+                                    (int) (0.95*adj->page_size));
+          
+        }
+
+      if ((int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
+        gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
+
       xg_ignore_gtk_scrollbar = 0;
       xg_ignore_gtk_scrollbar = 0;
+
+      /* Make GTK draw the new thumb.  We are not using a pure GTK event
+         loop so we need to do this.  */
+      gdk_window_process_all_updates ();
     }
 
     }
 
-  /* Make sure the scroll bar is redrawn with new thumb  */
-  gtk_widget_queue_draw (wscroll);
-  gdk_window_process_all_updates ();
-  xg_ignore_next_thumb = 0;
   UNBLOCK_INPUT;
 }
 
   UNBLOCK_INPUT;
 }
 
@@ -2667,7 +2814,7 @@ xg_tool_bar_help_callback (w, event, client_data)
     }
 
   if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
     }
 
   if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
-    return;
+    return FALSE;
 
   if (event->type == GDK_ENTER_NOTIFY)
     {
 
   if (event->type == GDK_ENTER_NOTIFY)
     {
@@ -2990,7 +3137,6 @@ void
 xg_initialize ()
 {
   xg_ignore_gtk_scrollbar = 0;
 xg_initialize ()
 {
   xg_ignore_gtk_scrollbar = 0;
-  xg_ignore_next_thumb = 0;
   xg_left_ptr_cursor = 0;
   xg_did_tearoff = 0;
 
   xg_left_ptr_cursor = 0;
   xg_did_tearoff = 0;