]> code.delx.au - gnu-emacs/blobdiff - src/xterm.c
(skip_chars): Setup gl_state (bug#3823).
[gnu-emacs] / src / xterm.c
index 94093bd3848abf4137ee35e3542aa65c601317cc..fd09d6d4815b6585cf3cdbbf4d5801d8dbc7f7f8 100644 (file)
@@ -1,6 +1,6 @@
 /* X Communication module for terminals which understand the X protocol.
    Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-                 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+                 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
                  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -753,11 +753,6 @@ x_after_update_window_line (desired_row)
     {
       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
 
-      /* Internal border is drawn below the tool bar.  */
-      if (WINDOWP (f->tool_bar_window)
-         && w == XWINDOW (f->tool_bar_window))
-       y -= width;
-
       BLOCK_INPUT;
       x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                    0, y, width, height, False);
@@ -1383,19 +1378,27 @@ x_draw_composite_glyph_string_foreground (s)
              if (j < i)
                {
                  font->driver->draw (s, j, i, x, y, 0);
+                 if (s->face->overstrike)
+                   font->driver->draw (s, j, i, x + 1, y, 0);
                  x += width;
                }
              xoff = LGLYPH_XOFF (glyph);
              yoff = LGLYPH_YOFF (glyph);
              wadjust = LGLYPH_WADJUST (glyph);
              font->driver->draw (s, i, i + 1, x + xoff, y + yoff, 0);
+             if (s->face->overstrike)
+               font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff, 0);
              x += wadjust;
              j = i + 1;
              width = 0;
            }
        }
       if (j < i)
-       font->driver->draw (s, j, i, x, y, 0);
+       {
+         font->driver->draw (s, j, i, x, y, 0);
+         if (s->face->overstrike)
+           font->driver->draw (s, j, i, x + 1, y, 0);
+       }
     }
 }
 
@@ -2951,6 +2954,12 @@ x_clear_frame (struct frame *f)
      colors or something like that, then they should be notified.  */
   x_scroll_bar_clear (f);
 
+#if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
+  /* Make sure scroll bars are redrawn.  As they aren't redrawn by
+     redisplay, do it here.  */
+  gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
+#endif
+  
   XFlush (FRAME_X_DISPLAY (f));
 
   UNBLOCK_INPUT;
@@ -3006,6 +3015,22 @@ XTflash (f)
   BLOCK_INPUT;
 
   {
+#ifdef USE_GTK
+    /* Use Gdk routines to draw.  This way, we won't draw over scroll bars
+       when the scroll bars and the edit widget share the same X window.  */
+    GdkGCValues vals;
+    GdkGC *gc;
+    vals.foreground.pixel = (FRAME_FOREGROUND_PIXEL (f)
+                             ^ FRAME_BACKGROUND_PIXEL (f));
+    vals.function = GDK_XOR;
+    gc = gdk_gc_new_with_values (FRAME_GTK_WIDGET (f)->window,
+                                 &vals,
+                                 GDK_GC_FUNCTION
+                                 | GDK_GC_FOREGROUND);
+#define XFillRectangle(d, win, gc, x, y, w, h) \
+    gdk_draw_rectangle (FRAME_GTK_WIDGET (f)->window, \
+                        gc, TRUE, x, y, w, h)
+#else
     GC gc;
 
     /* Create a GC that will use the GXxor function to flip foreground
@@ -3020,7 +3045,7 @@ XTflash (f)
       gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                      GCFunction | GCForeground, &values);
     }
-
+#endif
     {
       /* Get the height not including a menu bar widget.  */
       int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
@@ -3056,13 +3081,14 @@ XTflash (f)
          XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
                          flash_left,
                          (FRAME_INTERNAL_BORDER_WIDTH (f)
-                          + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
+                          + FRAME_TOP_MARGIN_HEIGHT (f)),
                          width, flash_height);
          XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
                          flash_left,
                          (height - flash_height
                           - FRAME_INTERNAL_BORDER_WIDTH (f)),
                          width, flash_height);
+
        }
       else
        /* If it is short, flash it all.  */
@@ -3110,7 +3136,7 @@ XTflash (f)
          XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
                          flash_left,
                          (FRAME_INTERNAL_BORDER_WIDTH (f)
-                          + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
+                          + FRAME_TOP_MARGIN_HEIGHT (f)),
                          width, flash_height);
          XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
                          flash_left,
@@ -3124,7 +3150,12 @@ XTflash (f)
                        flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
                        width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
 
+#ifdef USE_GTK
+      g_object_unref (G_OBJECT (gc));
+#undef XFillRectangle
+#else
       XFreeGC (FRAME_X_DISPLAY (f), gc);
+#endif
       x_flush (f);
     }
   }
@@ -4374,63 +4405,51 @@ xm_scroll_callback (widget, client_data, call_data)
 /* Scroll bar callback for GTK scroll bars.  WIDGET is the scroll
    bar widget.  DATA is a pointer to the scroll_bar structure. */
 
-static void
-xg_scroll_callback (widget, data)
-     GtkRange *widget;
-     gpointer data;
+static gboolean
+xg_scroll_callback (GtkRange     *range,
+                    GtkScrollType scroll,
+                    gdouble       value,
+                    gpointer      user_data)
 {
-  struct scroll_bar *bar = (struct scroll_bar *) data;
-  gdouble previous;
+  struct scroll_bar *bar = (struct scroll_bar *) user_data;
   gdouble position;
-  gdouble *p;
-  int diff;
-
   int part = -1, whole = 0, portion = 0;
-  GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (widget));
+  GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
+  FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (range), XG_FRAME_DATA);
 
+  if (xg_ignore_gtk_scrollbar) return FALSE;
   position = gtk_adjustment_get_value (adj);
 
-  p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
-  if (! p)
-    {
-      p = (gdouble*) xmalloc (sizeof (gdouble));
-      *p = XG_SB_MIN;
-      g_object_set_data (G_OBJECT (widget), XG_LAST_SB_DATA, p);
-    }
-
-  previous = *p;
-  *p = position;
-
-  if (xg_ignore_gtk_scrollbar) return;
-
-  diff = (int) (position - previous);
 
-  if (diff == (int) adj->step_increment)
-    {
-      part = scroll_bar_down_arrow;
-      bar->dragging = Qnil;
-    }
-  else if (-diff == (int) adj->step_increment)
+  switch (scroll)
     {
+    case GTK_SCROLL_JUMP:
+      /* Buttons 1 2 or 3 must be grabbed.  */
+      if (FRAME_X_DISPLAY_INFO (f)->grabbed != 0
+          && FRAME_X_DISPLAY_INFO (f)->grabbed < (1 << 4))
+        {
+          part = scroll_bar_handle;
+          whole = adj->upper - adj->page_size;
+          portion = min ((int)position, whole);
+          bar->dragging = make_number ((int)portion);
+        }
+      break;
+    case GTK_SCROLL_STEP_BACKWARD:
       part = scroll_bar_up_arrow;
       bar->dragging = Qnil;
-    }
-  else if (diff == (int) adj->page_increment)
-    {
-      part = scroll_bar_below_handle;
+      break;
+    case GTK_SCROLL_STEP_FORWARD:
+      part = scroll_bar_down_arrow;
       bar->dragging = Qnil;
-    }
-  else if (-diff == (int) adj->page_increment)
-    {
+      break;
+    case GTK_SCROLL_PAGE_BACKWARD:
       part = scroll_bar_above_handle;
       bar->dragging = Qnil;
-    }
-  else
-    {
-      part = scroll_bar_handle;
-      whole = adj->upper - adj->page_size;
-      portion = min ((int)position, whole);
-      bar->dragging = make_number ((int)portion);
+      break;
+    case GTK_SCROLL_PAGE_FORWARD:
+      part = scroll_bar_below_handle;
+      bar->dragging = Qnil;
+      break;
     }
 
   if (part >= 0)
@@ -4439,8 +4458,30 @@ xg_scroll_callback (widget, data)
       last_scroll_bar_part = part;
       x_send_scroll_bar_event (bar->window, part, portion, whole);
     }
+
+  return FALSE;
+}
+
+/* Callback for button release. Sets dragging to Qnil when dragging is done.  */
+
+static gboolean
+xg_end_scroll_callback (GtkWidget *widget,
+                        GdkEventButton *event,
+                        gpointer user_data)
+{
+  struct scroll_bar *bar = (struct scroll_bar *) user_data;
+  bar->dragging = Qnil;
+  if (WINDOWP (window_being_scrolled))
+    {
+      x_send_scroll_bar_event (window_being_scrolled,
+                               scroll_bar_end_scroll, 0, 0);
+      window_being_scrolled = Qnil;
+    }
+
+  return FALSE;
 }
 
+
 #else /* not USE_GTK and not USE_MOTIF */
 
 /* Xaw scroll bar callback.  Invoked when the thumb is dragged.
@@ -4541,6 +4582,7 @@ x_create_toolkit_scroll_bar (f, bar)
 
   BLOCK_INPUT;
   xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
+                        G_CALLBACK (xg_end_scroll_callback),
                         scroll_bar_name);
   UNBLOCK_INPUT;
 }
@@ -5777,6 +5819,7 @@ event_handler_gdk (gxev, ev, data)
 {
   XEvent *xev = (XEvent *) gxev;
 
+  BLOCK_INPUT;
   if (current_count >= 0)
     {
       struct x_display_info *dpyinfo;
@@ -5787,23 +5830,27 @@ event_handler_gdk (gxev, ev, data)
       /* Filter events for the current X input method.
          GTK calls XFilterEvent but not for key press and release,
          so we do it here.  */
-      if (xev->type == KeyPress || xev->type == KeyRelease)
-        if (dpyinfo && x_filter_event (dpyinfo, xev))
-          return GDK_FILTER_REMOVE;
+      if ((xev->type == KeyPress || xev->type == KeyRelease)
+         && dpyinfo
+         && x_filter_event (dpyinfo, xev))
+       {
+         UNBLOCK_INPUT;
+         return GDK_FILTER_REMOVE;
+       }
 #endif
 
       if (! dpyinfo)
         current_finish = X_EVENT_NORMAL;
       else
-       {
-         current_count +=
-           handle_one_xevent (dpyinfo, xev, &current_finish,
-                              current_hold_quit);
-       }
+       current_count +=
+         handle_one_xevent (dpyinfo, xev, &current_finish,
+                            current_hold_quit);
     }
   else
     current_finish = x_dispatch_event (xev, xev->xany.display);
 
+  UNBLOCK_INPUT;
+
   if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP)
     return GDK_FILTER_REMOVE;
 
@@ -7421,6 +7468,11 @@ x_clear_frame_area (f, x, y, width, height)
 {
   x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                x, y, width, height, False);
+#ifdef USE_GTK
+  /* Must queue a redraw, because scroll bars might have been cleared.  */
+  if (FRAME_GTK_WIDGET (f))
+    gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
+#endif
 }
 
 
@@ -8053,32 +8105,7 @@ x_new_font (f, font_object, fontset)
         doing it because it's done in Fx_show_tip, and it leads to
         problems because the tip frame has no widget.  */
       if (NILP (tip_frame) || XFRAME (tip_frame) != f)
-        {
-         int rows, cols;
-         
-         /* When the frame is maximized/fullscreen or running under for
-             example Xmonad, x_set_window_size will be a no-op.
-             In that case, the right thing to do is extend rows/cols to
-             the current frame size.  We do that first if x_set_window_size
-             turns out to not be a no-op (there is no way to know).
-             The size will be adjusted again if the frame gets a
-             ConfigureNotify event as a result of x_set_window_size.  */
-          int pixelh = FRAME_PIXEL_HEIGHT (f);
-#ifdef USE_X_TOOLKIT
-          /* The menu bar is not part of text lines.  The tool bar
-             is however.  */
-          pixelh -= FRAME_MENUBAR_HEIGHT (f);
-#endif
-          rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelh);
-         /* Update f->scroll_bar_actual_width because it is used in
-            FRAME_PIXEL_WIDTH_TO_TEXT_COLS.  */
-         f->scroll_bar_actual_width
-           = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
-          cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, FRAME_PIXEL_WIDTH (f));
-          
-          change_frame_size (f, rows, cols, 0, 1, 0);
-          x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
-        }
+        x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
     }
 
 #ifdef HAVE_X_I18N
@@ -8966,6 +8993,32 @@ x_set_window_size (f, change_gravity, cols, rows)
 {
   BLOCK_INPUT;
 
+  if (NILP (tip_frame) || XFRAME (tip_frame) != f)
+    {
+      int r, c;
+         
+      /* When the frame is maximized/fullscreen or running under for
+         example Xmonad, x_set_window_size_1 will be a no-op.
+         In that case, the right thing to do is extend rows/cols to
+         the current frame size.  We do that first if x_set_window_size_1
+         turns out to not be a no-op (there is no way to know).
+         The size will be adjusted again if the frame gets a
+         ConfigureNotify event as a result of x_set_window_size.  */
+      int pixelh = FRAME_PIXEL_HEIGHT (f);
+#ifdef USE_X_TOOLKIT
+      /* The menu bar is not part of text lines.  The tool bar
+         is however.  */
+      pixelh -= FRAME_MENUBAR_HEIGHT (f);
+#endif
+      r = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelh);
+      /* Update f->scroll_bar_actual_width because it is used in
+         FRAME_PIXEL_WIDTH_TO_TEXT_COLS.  */
+      f->scroll_bar_actual_width
+        = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
+      c = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, FRAME_PIXEL_WIDTH (f));
+      change_frame_size (f, r, c, 0, 1, 0);
+    }
+
 #ifdef USE_GTK
   if (FRAME_GTK_WIDGET (f))
     xg_frame_set_char_size (f, cols, rows);
@@ -9800,7 +9853,7 @@ x_wm_set_icon_pixmap (f, pixmap_id)
 {
   Pixmap icon_pixmap, icon_mask;
 
-#ifndef USE_X_TOOLKIT
+#if !defined USE_X_TOOLKIT && !defined USE_GTK
   Window window = FRAME_OUTER_WINDOW (f);
 #endif
 
@@ -10009,6 +10062,19 @@ x_display_ok (display)
     return dpy_ok;
 }
 
+#ifdef USE_GTK
+static void
+my_log_handler (log_domain, log_level, message, user_data)
+     const gchar *log_domain;
+     GLogLevelFlags log_level;
+     const gchar *message;
+     gpointer user_data;
+{
+  if (!strstr (message, "g_set_prgname"))
+      fprintf (stderr, "%s-WARNING **: %s\n", log_domain, message);
+}
+#endif
+  
 /* Open a connection to X display DISPLAY_NAME, and return
    the structure that describes the open display.
    If we cannot contact the display, return null.  */
@@ -10042,8 +10108,7 @@ x_term_init (display_name, xrm_option, resource_name)
     int argc;
     char *argv[NUM_ARGV];
     char **argv2 = argv;
-    GdkAtom atom;
-
+    guint id;
 #ifndef HAVE_GTK_MULTIDISPLAY
     if (!EQ (Vinitial_window_system, Qx))
       error ("Sorry, you cannot connect to X servers with the GTK toolkit");
@@ -10078,7 +10143,12 @@ x_term_init (display_name, xrm_option, resource_name)
 
         XSetLocaleModifiers ("");
 
+        /* Work around GLib bug that outputs a faulty warning. See
+           https://bugzilla.gnome.org/show_bug.cgi?id=563627.  */
+        id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
+                                  | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
         gtk_init (&argc, &argv2);
+        g_log_remove_handler ("GLib", id);
 
         /* gtk_init does set_locale.  We must fix locale after calling it.  */
         fixup_locale ();
@@ -10176,10 +10246,25 @@ x_term_init (display_name, xrm_option, resource_name)
        terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
        init_kboard (terminal->kboard);
        terminal->kboard->Vwindow_system = Qx;
+
+       /* Add the keyboard to the list before running Lisp code (via
+           Qvendor_specific_keysyms below), since these are not traced
+           via terminals but only through all_kboards.  */
+       terminal->kboard->next_kboard = all_kboards;
+       all_kboards = terminal->kboard;
+
        if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
          {
            char *vendor = ServerVendor (dpy);
-           /* Temporarily hide the partially initialized terminal */
+
+           /* Protect terminal from GC before removing it from the
+              list of terminals.  */
+           struct gcpro gcpro1;
+           Lisp_Object gcpro_term;
+           XSETTERMINAL (gcpro_term, terminal);
+           GCPRO1 (gcpro_term);
+
+           /* Temporarily hide the partially initialized terminal.  */
            terminal_list = terminal->next_terminal;
            UNBLOCK_INPUT;
            terminal->kboard->Vsystem_key_alist
@@ -10188,10 +10273,9 @@ x_term_init (display_name, xrm_option, resource_name)
            BLOCK_INPUT;
            terminal->next_terminal = terminal_list;
            terminal_list = terminal;
+           UNGCPRO;
          }
 
-       terminal->kboard->next_kboard = all_kboards;
-       all_kboards = terminal->kboard;
        /* Don't let the initial kboard remain current longer than necessary.
           That would cause problems if a file loaded on startup tries to
           prompt in the mini-buffer.  */
@@ -10416,7 +10500,11 @@ x_term_init (display_name, xrm_option, resource_name)
     = XInternAtom (dpyinfo->display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
   dpyinfo->Xatom_net_wm_state_sticky
     = XInternAtom (dpyinfo->display, "_NET_WM_STATE_STICKY", False);
-
+  dpyinfo->Xatom_net_window_type
+    = XInternAtom (dpyinfo->display, "_NET_WM_WINDOW_TYPE", False);
+  dpyinfo->Xatom_net_window_type_tooltip
+    = XInternAtom (dpyinfo->display, "_NET_WM_WINDOW_TYPE_TOOLTIP", False);
+  
   dpyinfo->cut_buffers_initialized = 0;
 
   dpyinfo->x_dnd_atoms_size = 8;
@@ -10536,7 +10624,6 @@ void
 x_delete_display (dpyinfo)
      struct x_display_info *dpyinfo;
 {
-  int i;
   struct terminal *t;
 
   /* Close all frames and delete the generic struct terminal for this
@@ -10688,7 +10775,6 @@ void
 x_delete_terminal (struct terminal *terminal)
 {
   struct x_display_info *dpyinfo = terminal->display_info.x;
-  int i;
 
   /* Protect against recursive calls.  delete_frame in
      delete_terminal calls us back when it deletes our last frame.  */
@@ -10747,6 +10833,8 @@ x_delete_terminal (struct terminal *terminal)
 #endif /* ! USE_GTK */
     }
 
+  /* Mark as dead. */
+  dpyinfo->display = NULL;
   x_delete_display (dpyinfo);
   UNBLOCK_INPUT;
 }