/* X Communication module for terminals which understand the X protocol.
-Copyright (C) 1989, 1993-2014 Free Software Foundation, Inc.
+Copyright (C) 1989, 1993-2015 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "xterm.h"
#include <X11/cursorfont.h>
+/* If we have Xfixes extension, use it for pointer blanking. */
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+
+/* Using Xft implies that XRender is available. */
+#ifdef HAVE_XFT
+#include <X11/extensions/Xrender.h>
+#endif
+
/* Load sys/types.h if not already loaded.
In some systems loading it twice is suicidal. */
#ifndef makedev
#include "xsettings.h"
#include "xgselect.h"
#include "sysselect.h"
+#include "menu.h"
#ifdef USE_X_TOOLKIT
#include <X11/Shell.h>
};
static bool x_alloc_nearest_color_1 (Display *, Colormap, XColor *);
-static void x_set_window_size_1 (struct frame *, int, int, int, bool);
+static void x_set_window_size_1 (struct frame *, bool, int, int, bool);
static void x_raise_frame (struct frame *);
static void x_lower_frame (struct frame *);
static const XColor *x_color_cells (Display *, int *);
static int x_io_error_quitter (Display *);
static struct terminal *x_create_terminal (struct x_display_info *);
-void x_delete_terminal (struct terminal *);
static void x_update_end (struct frame *);
static void XTframe_up_to_date (struct frame *);
static void x_clear_frame (struct frame *);
static void x_flush (struct frame *f);
static void x_update_begin (struct frame *);
static void x_update_window_begin (struct window *);
-static struct scroll_bar *x_window_to_scroll_bar (Display *, Window);
+static struct scroll_bar *x_window_to_scroll_bar (Display *, Window, int);
static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *,
enum scroll_bar_part *,
Lisp_Object *, Lisp_Object *,
Time *);
-static int x_handle_net_wm_state (struct frame *, const XPropertyEvent *);
+static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object *,
+ enum scroll_bar_part *,
+ Lisp_Object *, Lisp_Object *,
+ Time *);
+static bool x_handle_net_wm_state (struct frame *, const XPropertyEvent *);
static void x_check_fullscreen (struct frame *);
static void x_check_expected_move (struct frame *, int, int);
-static void x_sync_with_move (struct frame *, int, int, int);
+static void x_sync_with_move (struct frame *, int, int, bool);
static int handle_one_xevent (struct x_display_info *,
const XEvent *, int *,
struct input_event *);
static void x_wm_set_icon_pixmap (struct frame *, ptrdiff_t);
static void x_initialize (void);
+static bool get_current_wm_state (struct frame *, Window, int *, bool *);
/* Flush display of frame F. */
Debugging
***********************************************************************/
-#if 0
+#if false
/* This is a function useful for recording debugging information about
the sequence of occurrences in this file. */
void
record_event (char *locus, int type)
{
- if (event_record_index == sizeof (event_record) / sizeof (struct record))
+ if (event_record_index == ARRAYELTS (event_record))
event_record_index = 0;
event_record[event_record_index].locus = locus;
event_record_index++;
}
-#endif /* 0 */
+#endif
\f
unsigned int nchildren;
win = wi;
- XQueryTree (dpy, win, &root, &wi, &children, &nchildren);
- XFree (children);
+ if (XQueryTree (dpy, win, &root, &wi, &children, &nchildren))
+ XFree (children);
+ else
+ break;
}
return win;
if (parent != None)
XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
XA_CARDINAL, 32, PropModeReplace,
- (unsigned char *) &opac, 1L);
+ (unsigned char *) &opac, 1);
/* return unless necessary */
{
unsigned long n, left;
rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
- 0L, 1L, False, XA_CARDINAL,
+ 0, 1, False, XA_CARDINAL,
&actual, &format, &n, &left,
&data);
XChangeProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
XA_CARDINAL, 32, PropModeReplace,
- (unsigned char *) &opac, 1L);
+ (unsigned char *) &opac, 1);
x_uncatch_errors ();
}
-int
-x_display_pixel_height (struct x_display_info *dpyinfo)
-{
- return HeightOfScreen (dpyinfo->screen);
-}
-
-int
-x_display_pixel_width (struct x_display_info *dpyinfo)
-{
- return WidthOfScreen (dpyinfo->screen);
-}
-
-\f
/***********************************************************************
Starting and ending an update
***********************************************************************/
if (f == hlinfo->mouse_face_mouse_frame)
{
/* Don't do highlighting for mouse motion during the update. */
- hlinfo->mouse_face_defer = 1;
+ hlinfo->mouse_face_defer = true;
/* If F needs to be redrawn, simply forget about any prior mouse
highlighting. */
block_input ();
if (cursor_on_p)
- display_and_set_cursor (w, 1,
+ display_and_set_cursor (w, true,
w->output_cursor.hpos, w->output_cursor.vpos,
w->output_cursor.x, w->output_cursor.y);
- if (draw_window_fringes (w, 1))
+ if (draw_window_fringes (w, true))
{
if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
x_draw_right_divider (w);
x_update_end (struct frame *f)
{
/* Mouse highlight may be displayed again. */
- MOUSE_HL_INFO (f)->mouse_face_defer = 0;
+ MOUSE_HL_INFO (f)->mouse_face_defer = false;
#ifndef XFlush
block_input ();
}
-/* Clear under internal border if any for non-toolkit builds. */
-
-
-#if !defined USE_X_TOOLKIT && !defined USE_GTK
+/* Clear under internal border if any (GTK has its own version). */
+#ifndef USE_GTK
void
x_clear_under_internal_border (struct frame *f)
{
eassert (w);
if (!desired_row->mode_line_p && !w->pseudo_window_p)
- desired_row->redraw_fringe_bitmaps_p = 1;
+ desired_row->redraw_fringe_bitmaps_p = true;
#ifdef USE_X_TOOLKIT
/* When a window has disappeared, make sure that no rest of
static void x_clear_glyph_string_rect (struct glyph_string *, int,
int, int, int);
static void x_draw_relief_rect (struct frame *, int, int, int, int,
- int, int, int, int, int, int,
+ int, bool, bool, bool, bool, bool,
XRectangle *);
static void x_draw_box_rect (struct glyph_string *, int, int, int, int,
- int, int, int, XRectangle *);
+ int, bool, bool, XRectangle *);
static void x_scroll_bar_clear (struct frame *);
#ifdef GLYPH_DEBUG
else
face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
s->face = FACE_FROM_ID (s->f, face_id);
- PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
+ prepare_face_for_display (s->f, s->face);
if (s->font == s->face->font)
s->gc = s->face->gc;
static void
x_set_glyph_string_gc (struct glyph_string *s)
{
- PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
+ prepare_face_for_display (s->f, s->face);
if (s->hl == DRAW_NORMAL_TEXT)
{
else if (s->hl == DRAW_CURSOR)
{
x_set_cursor_gc (s);
- s->stippled_p = 0;
+ s->stippled_p = false;
}
else if (s->hl == DRAW_MOUSE_FACE)
{
s->stippled_p = s->face->stipple != 0;
}
else
- {
- s->gc = s->face->gc;
- s->stippled_p = s->face->stipple != 0;
- }
+ emacs_abort ();
/* GC must have been set. */
eassert (s->gc != 0);
s->background_width,
s->height - 2 * box_line_width);
XSetFillStyle (s->display, s->gc, FillSolid);
- s->background_filled_p = 1;
+ s->background_filled_p = true;
}
else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
|| s->font_not_found_p
x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
s->background_width,
s->height - 2 * box_line_width);
- s->background_filled_p = 1;
+ s->background_filled_p = true;
}
}
}
y = s->ybase - boff;
if (s->for_overlaps
|| (s->background_filled_p && s->hl != DRAW_CURSOR))
- font->driver->draw (s, 0, s->nchars, x, y, 0);
+ font->driver->draw (s, 0, s->nchars, x, y, false);
else
- font->driver->draw (s, 0, s->nchars, x, y, 1);
+ font->driver->draw (s, 0, s->nchars, x, y, true);
if (s->face->overstrike)
- font->driver->draw (s, 0, s->nchars, x + 1, y, 0);
+ font->driver->draw (s, 0, s->nchars, x + 1, y, false);
}
}
int xx = x + s->cmp->offsets[j * 2];
int yy = y - s->cmp->offsets[j * 2 + 1];
- font->driver->draw (s, j, j + 1, xx, yy, 0);
+ font->driver->draw (s, j, j + 1, xx, yy, false);
if (s->face->overstrike)
- font->driver->draw (s, j, j + 1, xx + 1, yy, 0);
+ font->driver->draw (s, j, j + 1, xx + 1, yy, false);
}
}
else
if (j < i)
{
- font->driver->draw (s, j, i, x, y, 0);
+ font->driver->draw (s, j, i, x, y, false);
if (s->face->overstrike)
- font->driver->draw (s, j, i, x + 1, y, 0);
+ font->driver->draw (s, j, i, x + 1, y, false);
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);
+ font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
if (s->face->overstrike)
- font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff, 0);
+ font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
+ false);
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, false);
if (s->face->overstrike)
- font->driver->draw (s, j, i, x + 1, y, 0);
+ font->driver->draw (s, j, i, x + 1, y, false);
}
}
}
s->font->driver->draw (s, 0, upper_len,
x + glyph->slice.glyphless.upper_xoff,
s->ybase + glyph->slice.glyphless.upper_yoff,
- 0);
+ false);
s->font->driver->draw (s, upper_len, len,
x + glyph->slice.glyphless.lower_xoff,
s->ybase + glyph->slice.glyphless.lower_yoff,
- 0);
+ false);
}
if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
XDrawRectangle (s->display, s->window, s->gc,
success_p = x_alloc_nearest_color (f, cmap, &new);
}
else
- success_p = 1;
+ success_p = true;
*pixel = new.pixel;
}
/* Draw a relief on frame F inside the rectangle given by LEFT_X,
TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
- to draw, it must be >= 0. RAISED_P non-zero means draw a raised
- relief. LEFT_P non-zero means draw a relief on the left side of
- the rectangle. RIGHT_P non-zero means draw a relief on the right
+ to draw, it must be >= 0. RAISED_P means draw a raised
+ relief. LEFT_P means draw a relief on the left side of
+ the rectangle. RIGHT_P means draw a relief on the right
side of the rectangle. CLIP_RECT is the clipping rectangle to use
when drawing. */
static void
x_draw_relief_rect (struct frame *f,
- int left_x, int top_y, int right_x, int bottom_y, int width,
- int raised_p, int top_p, int bot_p, int left_p, int right_p,
+ int left_x, int top_y, int right_x, int bottom_y,
+ int width, bool raised_p, bool top_p, bool bot_p,
+ bool left_p, bool right_p,
XRectangle *clip_rect)
{
Display *dpy = FRAME_X_DISPLAY (f);
{
if (width == 1)
XDrawLine (dpy, window, gc,
- left_x + (left_p ? 1 : 0), top_y,
- right_x + (right_p ? 0 : 1), top_y);
+ left_x + left_p, top_y,
+ right_x + !right_p, top_y);
for (i = 1; i < width; ++i)
XDrawLine (dpy, window, gc,
/* Outermost top line. */
if (top_p)
XDrawLine (dpy, window, gc,
- left_x + (left_p ? 1 : 0), top_y,
- right_x + (right_p ? 0 : 1), top_y);
+ left_x + left_p, top_y,
+ right_x + !right_p, top_y);
/* Outermost left line. */
if (left_p)
if (bot_p)
{
XDrawLine (dpy, window, gc,
- left_x + (left_p ? 1 : 0), bottom_y,
- right_x + (right_p ? 0 : 1), bottom_y);
+ left_x + left_p, bottom_y,
+ right_x + !right_p, bottom_y);
for (i = 1; i < width; ++i)
XDrawLine (dpy, window, gc,
left_x + i * left_p, bottom_y - i,
/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
- draw, it must be >= 0. LEFT_P non-zero means draw a line on the
- left side of the rectangle. RIGHT_P non-zero means draw a line
+ draw, it must be >= 0. LEFT_P means draw a line on the
+ left side of the rectangle. RIGHT_P means draw a line
on the right side of the rectangle. CLIP_RECT is the clipping
rectangle to use when drawing. */
static void
x_draw_box_rect (struct glyph_string *s,
int left_x, int top_y, int right_x, int bottom_y, int width,
- int left_p, int right_p, XRectangle *clip_rect)
+ bool left_p, bool right_p, XRectangle *clip_rect)
{
XGCValues xgcv;
static void
x_draw_glyph_string_box (struct glyph_string *s)
{
- int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
- int left_p, right_p;
+ int width, left_x, right_x, top_y, bottom_y, last_x;
+ bool raised_p, left_p, right_p;
struct glyph *last_glyph;
XRectangle clip_rect;
{
x_setup_relief_colors (s);
x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
- width, raised_p, 1, 1, left_p, right_p, &clip_rect);
+ width, raised_p, true, true, left_p, right_p,
+ &clip_rect);
}
}
static void
x_draw_image_relief (struct glyph_string *s)
{
- int x1, y1, thick, raised_p, top_p, bot_p, left_p, right_p;
+ int x1, y1, thick;
+ bool raised_p, top_p, bot_p, left_p, right_p;
int extra_x, extra_y;
XRectangle r;
int x = s->x;
extra_x = extra_y = XINT (Vtool_bar_button_margin);
}
- top_p = bot_p = left_p = right_p = 0;
+ top_p = bot_p = left_p = right_p = false;
if (s->slice.x == 0)
- x -= thick + extra_x, left_p = 1;
+ x -= thick + extra_x, left_p = true;
if (s->slice.y == 0)
- y -= thick + extra_y, top_p = 1;
+ y -= thick + extra_y, top_p = true;
if (s->slice.x + s->slice.width == s->img->width)
- x1 += thick + extra_x, right_p = 1;
+ x1 += thick + extra_x, right_p = true;
if (s->slice.y + s->slice.height == s->img->height)
- y1 += thick + extra_y, bot_p = 1;
+ y1 += thick + extra_y, bot_p = true;
x_setup_relief_colors (s);
get_glyph_string_clip_rect (s, &r);
x_draw_glyph_string_bg_rect (s, x, y, width, height);
}
- s->background_filled_p = 1;
+ s->background_filled_p = true;
}
/* Draw the foreground. */
x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
}
- s->background_filled_p = 1;
+ s->background_filled_p = true;
}
/*
x_draw_underwave (struct glyph_string *s)
{
int wave_height = 3, wave_length = 2;
- int dx, dy, x0, y0, width, x1, y1, x2, y2, odd, xmax;
+ int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax;
+ bool odd;
XRectangle wave_clip, string_clip, final_clip;
dx = wave_length;
x1 = x0 - (x0 % dx);
x2 = x1 + dx;
- odd = (x1/dx) % 2;
+ odd = (x1 / dx) & 1;
y1 = y2 = y0;
if (odd)
static void
x_draw_glyph_string (struct glyph_string *s)
{
- bool relief_drawn_p = 0;
+ bool relief_drawn_p = false;
/* If S draws into the background of its successors, draw the
background of the successors first so that S can draw into it.
if (next->first_glyph->type == STRETCH_GLYPH)
x_draw_stretch_glyph_string (next);
else
- x_draw_glyph_string_background (next, 1);
+ x_draw_glyph_string_background (next, true);
next->num_clips = 0;
}
}
{
x_set_glyph_string_clipping (s);
- x_draw_glyph_string_background (s, 1);
+ x_draw_glyph_string_background (s, true);
x_draw_glyph_string_box (s);
x_set_glyph_string_clipping (s);
- relief_drawn_p = 1;
+ relief_drawn_p = true;
}
else if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */
&& !s->clip_tail
case CHAR_GLYPH:
if (s->for_overlaps)
- s->background_filled_p = 1;
+ s->background_filled_p = true;
else
- x_draw_glyph_string_background (s, 0);
+ x_draw_glyph_string_background (s, false);
x_draw_glyph_string_foreground (s);
break;
case COMPOSITE_GLYPH:
if (s->for_overlaps || (s->cmp_from > 0
&& ! s->first_glyph->u.cmp.automatic))
- s->background_filled_p = 1;
+ s->background_filled_p = true;
else
- x_draw_glyph_string_background (s, 1);
+ x_draw_glyph_string_background (s, true);
x_draw_composite_glyph_string_foreground (s);
break;
case GLYPHLESS_GLYPH:
if (s->for_overlaps)
- s->background_filled_p = 1;
+ s->background_filled_p = true;
else
- x_draw_glyph_string_background (s, 1);
+ x_draw_glyph_string_background (s, true);
x_draw_glyphless_glyph_string_foreground (s);
break;
unblock_input ();
}
+/* RIF: Show hourglass cursor on frame F. */
+
+static void
+x_show_hourglass (struct frame *f)
+{
+ Display *dpy = FRAME_X_DISPLAY (f);
+
+ if (dpy)
+ {
+ struct x_output *x = FRAME_X_OUTPUT (f);
+#ifdef USE_X_TOOLKIT
+ if (x->widget)
+#else
+ if (FRAME_OUTER_WINDOW (f))
+#endif
+ {
+ x->hourglass_p = true;
+
+ if (!x->hourglass_window)
+ {
+ unsigned long mask = CWCursor;
+ XSetWindowAttributes attrs;
+#ifdef USE_GTK
+ Window parent = FRAME_X_WINDOW (f);
+#else
+ Window parent = FRAME_OUTER_WINDOW (f);
+#endif
+ attrs.cursor = x->hourglass_cursor;
+
+ x->hourglass_window = XCreateWindow
+ (dpy, parent, 0, 0, 32000, 32000, 0, 0,
+ InputOnly, CopyFromParent, mask, &attrs);
+ }
+
+ XMapRaised (dpy, x->hourglass_window);
+ XFlush (dpy);
+ }
+ }
+}
+
+/* RIF: Cancel hourglass cursor on frame F. */
+
+static void
+x_hide_hourglass (struct frame *f)
+{
+ struct x_output *x = FRAME_X_OUTPUT (f);
+
+ /* Watch out for newly created frames. */
+ if (x->hourglass_window)
+ {
+ XUnmapWindow (FRAME_X_DISPLAY (f), x->hourglass_window);
+ /* Sync here because XTread_socket looks at the
+ hourglass_p flag that is reset to zero below. */
+ XSync (FRAME_X_DISPLAY (f), False);
+ x->hourglass_p = false;
+ }
+}
-\f
/* Invert the middle quarter of the frame for .15 sec. */
static void
cairo_rectangle (cr, x, y, w, h); \
cairo_fill (cr); \
} \
- while (0)
+ while (false)
#else /* ! HAVE_GTK3 */
GdkGCValues vals;
GdkGC *gc;
static void
-XTtoggle_invisible_pointer (struct frame *f, int invisible)
+XTtoggle_invisible_pointer (struct frame *f, bool invisible)
{
block_input ();
- if (invisible)
- {
- if (FRAME_DISPLAY_INFO (f)->invisible_cursor != 0)
- XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- FRAME_DISPLAY_INFO (f)->invisible_cursor);
- }
- else
- XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- f->output_data.x->current_cursor);
- f->pointer_invisible = invisible;
+ FRAME_DISPLAY_INFO (f)->toggle_visible_pointer (f, invisible);
unblock_input ();
}
f->output_data.x->border_pixel);
x_uncatch_errors ();
unblock_input ();
- x_update_cursor (f, 1);
+ x_update_cursor (f, true);
x_set_frame_alpha (f);
}
f->output_data.x->border_tile);
x_uncatch_errors ();
unblock_input ();
- x_update_cursor (f, 1);
+ x_update_cursor (f, true);
x_set_frame_alpha (f);
}
XUnsetICFocus (FRAME_XIC (frame));
#endif
if (frame->pointer_invisible)
- XTtoggle_invisible_pointer (frame, 0);
+ XTtoggle_invisible_pointer (frame, false);
}
}
Alt keysyms are on. */
{
int row, col; /* The row and column in the modifier table. */
- int found_alt_or_meta;
+ bool found_alt_or_meta;
for (row = 3; row < 8; row++)
{
- found_alt_or_meta = 0;
+ found_alt_or_meta = false;
for (col = 0; col < mods->max_keypermod; col++)
{
KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col];
{
case XK_Meta_L:
case XK_Meta_R:
- found_alt_or_meta = 1;
+ found_alt_or_meta = true;
dpyinfo->meta_mod_mask |= (1 << row);
break;
case XK_Alt_L:
case XK_Alt_R:
- found_alt_or_meta = 1;
+ found_alt_or_meta = true;
dpyinfo->alt_mod_mask |= (1 << row);
break;
the mainstream emacs code by setting mouse_moved. If not, ask for
another motion event, so we can check again the next time it moves. */
-static int
+static bool
note_mouse_movement (struct frame *frame, const XMotionEvent *event)
{
XRectangle *r;
struct x_display_info *dpyinfo;
if (!FRAME_X_OUTPUT (frame))
- return 0;
+ return false;
dpyinfo = FRAME_DISPLAY_INFO (frame);
dpyinfo->last_mouse_movement_time = event->time;
if (event->window != FRAME_X_WINDOW (frame))
{
- frame->mouse_moved = 1;
+ frame->mouse_moved = true;
dpyinfo->last_mouse_scroll_bar = NULL;
note_mouse_highlight (frame, -1, -1);
dpyinfo->last_mouse_glyph_frame = NULL;
- return 1;
+ return true;
}
|| event->x < r->x || event->x >= r->x + r->width
|| event->y < r->y || event->y >= r->y + r->height)
{
- frame->mouse_moved = 1;
+ frame->mouse_moved = true;
dpyinfo->last_mouse_scroll_bar = NULL;
note_mouse_highlight (frame, event->x, event->y);
/* Remember which glyph we're now on. */
remember_mouse_glyph (frame, event->x, event->y, r);
dpyinfo->last_mouse_glyph_frame = frame;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/* Return the current position of the mouse.
block_input ();
if (dpyinfo->last_mouse_scroll_bar && insist == 0)
- x_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
+ {
+ struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
+
+ if (bar->horizontal)
+ x_horizontal_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
+ else
+ x_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
+ }
else
{
Window root;
FOR_EACH_FRAME (tail, frame)
if (FRAME_X_P (XFRAME (frame))
&& FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
- XFRAME (frame)->mouse_moved = 0;
+ XFRAME (frame)->mouse_moved = false;
dpyinfo->last_mouse_scroll_bar = NULL;
}
else
{
- while (1)
+ while (true)
{
XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
{
struct scroll_bar *bar;
- bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win);
+ bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win, 2);
if (bar)
{
dpyinfo->last_mouse_glyph_frame = f1;
*bar_window = Qnil;
- *part = 0;
+ *part = scroll_bar_above_handle;
*fp = f1;
XSETINT (*x, win_x);
XSETINT (*y, win_y);
bits. */
static struct scroll_bar *
-x_window_to_scroll_bar (Display *display, Window window_id)
+x_window_to_scroll_bar (Display *display, Window window_id, int type)
{
Lisp_Object tail, frame;
condemned = Qnil,
! NILP (bar));
bar = XSCROLL_BAR (bar)->next)
- if (XSCROLL_BAR (bar)->x_window == window_id &&
- FRAME_X_DISPLAY (XFRAME (frame)) == display)
+ if (XSCROLL_BAR (bar)->x_window == window_id
+ && FRAME_X_DISPLAY (XFRAME (frame)) == display
+ && (type = 2
+ || (type == 1 && XSCROLL_BAR (bar)->horizontal)
+ || (type == 0 && !XSCROLL_BAR (bar)->horizontal)))
return XSCROLL_BAR (bar);
}
#ifdef USE_TOOLKIT_SCROLL_BARS
-static void x_send_scroll_bar_event (Lisp_Object, int, int, int);
+static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part,
+ int, int, bool);
/* Lisp window being scrolled. Set when starting to interact with
a toolkit scroll bar, reset to nil when ending the interaction. */
/* Id of action hook installed for scroll bars. */
static XtActionHookId action_hook_id;
+static XtActionHookId horizontal_action_hook_id;
static Boolean xaw3d_arrow_scroll;
xt_action_hook (Widget widget, XtPointer client_data, String action_name,
XEvent *event, String *params, Cardinal *num_params)
{
- int scroll_bar_p;
+ bool scroll_bar_p;
const char *end_action;
#ifdef USE_MOTIF
struct scroll_bar *bar;
x_send_scroll_bar_event (window_being_scrolled,
- scroll_bar_end_scroll, 0, 0);
+ scroll_bar_end_scroll, 0, 0, false);
w = XWINDOW (window_being_scrolled);
bar = XSCROLL_BAR (w->vertical_scroll_bar);
bar->last_seen_part = scroll_bar_nowhere;
#endif
/* Xt timeouts no longer needed. */
- toolkit_scroll_bar_interaction = 0;
+ toolkit_scroll_bar_interaction = false;
+ }
+}
+
+
+static void
+xt_horizontal_action_hook (Widget widget, XtPointer client_data, String action_name,
+ XEvent *event, String *params, Cardinal *num_params)
+{
+ bool scroll_bar_p;
+ const char *end_action;
+
+#ifdef USE_MOTIF
+ scroll_bar_p = XmIsScrollBar (widget);
+ end_action = "Release";
+#else /* !USE_MOTIF i.e. use Xaw */
+ scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
+ end_action = "EndScroll";
+#endif /* USE_MOTIF */
+
+ if (scroll_bar_p
+ && strcmp (action_name, end_action) == 0
+ && WINDOWP (window_being_scrolled))
+ {
+ struct window *w;
+ struct scroll_bar *bar;
+
+ x_send_scroll_bar_event (window_being_scrolled,
+ scroll_bar_end_scroll, 0, 0, true);
+ w = XWINDOW (window_being_scrolled);
+ bar = XSCROLL_BAR (w->horizontal_scroll_bar);
+
+ if (bar->dragging != -1)
+ {
+ bar->dragging = -1;
+ /* The thumb size is incorrect while dragging: fix it. */
+ set_horizontal_scroll_bar (w);
+ }
+ window_being_scrolled = Qnil;
+#if defined (USE_LUCID)
+ bar->last_seen_part = scroll_bar_nowhere;
+#endif
+ /* Xt timeouts no longer needed. */
+ toolkit_scroll_bar_interaction = false;
}
}
#endif /* not USE_GTK */
amount to scroll of a whole of WHOLE. */
static void
-x_send_scroll_bar_event (Lisp_Object window, int part, int portion, int whole)
+x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part,
+ int portion, int whole, bool horizontal)
{
XEvent event;
XClientMessageEvent *ev = &event.xclient;
/* Construct a ClientMessage event to send to the frame. */
ev->type = ClientMessage;
- ev->message_type = FRAME_DISPLAY_INFO (f)->Xatom_Scrollbar;
+ ev->message_type = (horizontal
+ ? FRAME_DISPLAY_INFO (f)->Xatom_Horizontal_Scrollbar
+ : FRAME_DISPLAY_INFO (f)->Xatom_Scrollbar);
ev->display = FRAME_X_DISPLAY (f);
ev->window = FRAME_X_WINDOW (f);
ev->format = 32;
/* Make Xt timeouts work while the scroll bar is active. */
#ifdef USE_X_TOOLKIT
- toolkit_scroll_bar_interaction = 1;
+ toolkit_scroll_bar_interaction = true;
x_activate_timeout_atimer ();
#endif
ievent->modifiers = 0;
}
+/* Transform a horizontal scroll bar ClientMessage EVENT to an Emacs
+ input event in *IEVENT. */
+
+static void
+x_horizontal_scroll_bar_to_input_event (const XEvent *event,
+ struct input_event *ievent)
+{
+ const XClientMessageEvent *ev = &event->xclient;
+ Lisp_Object window;
+ struct window *w;
+
+ /* See the comment in the function above. */
+ intptr_t iw0 = ev->data.l[0];
+ intptr_t iw1 = ev->data.l[1];
+ intptr_t iw = (iw0 << 31 << 1) + (iw1 & 0xffffffffu);
+ w = (struct window *) iw;
+
+ XSETWINDOW (window, w);
+
+ ievent->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
+ ievent->frame_or_window = window;
+ ievent->arg = Qnil;
+#ifdef USE_GTK
+ ievent->timestamp = CurrentTime;
+#else
+ ievent->timestamp =
+ XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame)));
+#endif
+ ievent->code = 0;
+ ievent->part = ev->data.l[2];
+ ievent->x = make_number (ev->data.l[3]);
+ ievent->y = make_number (ev->data.l[4]);
+ ievent->modifiers = 0;
+}
+
#ifdef USE_MOTIF
#define XM_SB_MAX 10000000
-
/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
CALL_DATA is a pointer to a XmScrollBarCallbackStruct. */
{
struct scroll_bar *bar = client_data;
XmScrollBarCallbackStruct *cs = call_data;
- int part = -1, whole = 0, portion = 0;
+ enum scroll_bar_part part = scroll_bar_nowhere;
+ bool horizontal = bar->horizontal;
+ int whole = 0, portion = 0;
switch (cs->reason)
{
case XmCR_DECREMENT:
bar->dragging = -1;
- part = scroll_bar_up_arrow;
+ part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow;
break;
case XmCR_INCREMENT:
bar->dragging = -1;
- part = scroll_bar_down_arrow;
+ part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow;
break;
case XmCR_PAGE_DECREMENT:
bar->dragging = -1;
- part = scroll_bar_above_handle;
+ part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle;
break;
case XmCR_PAGE_INCREMENT:
bar->dragging = -1;
- part = scroll_bar_below_handle;
+ part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle;
break;
case XmCR_TO_TOP:
bar->dragging = -1;
- part = scroll_bar_to_top;
+ part = horizontal ? scroll_bar_to_leftmost : scroll_bar_to_top;
break;
case XmCR_TO_BOTTOM:
bar->dragging = -1;
- part = scroll_bar_to_bottom;
+ part = horizontal ? scroll_bar_to_rightmost : scroll_bar_to_bottom;
break;
case XmCR_DRAG:
{
int slider_size;
- /* Get the slider size. */
block_input ();
XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
unblock_input ();
- whole = XM_SB_MAX - slider_size;
- portion = min (cs->value, whole);
- part = scroll_bar_handle;
+ if (horizontal)
+ {
+ portion = bar->whole * ((float)cs->value / XM_SB_MAX);
+ whole = bar->whole * ((float)(XM_SB_MAX - slider_size) / XM_SB_MAX);
+ portion = min (portion, whole);
+ part = scroll_bar_horizontal_handle;
+ }
+ else
+ {
+ whole = XM_SB_MAX - slider_size;
+ portion = min (cs->value, whole);
+ part = scroll_bar_handle;
+ }
+
bar->dragging = cs->value;
}
break;
break;
};
- if (part >= 0)
+ if (part != scroll_bar_nowhere)
{
window_being_scrolled = bar->window;
- x_send_scroll_bar_event (bar->window, part, portion, whole);
+ x_send_scroll_bar_event (bar->window, part, portion, whole,
+ bar->horizontal);
}
}
gdouble value,
gpointer user_data)
{
+ int whole = 0, portion = 0;
struct scroll_bar *bar = user_data;
- int part = -1, whole = 0, portion = 0;
+ enum scroll_bar_part part = scroll_bar_nowhere;
GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
struct frame *f = g_object_get_data (G_OBJECT (range), XG_FRAME_DATA);
if (FRAME_DISPLAY_INFO (f)->grabbed != 0
&& FRAME_DISPLAY_INFO (f)->grabbed < (1 << 4))
{
- part = scroll_bar_handle;
- whole = gtk_adjustment_get_upper (adj) -
- gtk_adjustment_get_page_size (adj);
- portion = min ((int)value, whole);
- bar->dragging = portion;
- }
+ if (bar->horizontal)
+ {
+ part = scroll_bar_horizontal_handle;
+ whole = (int)(gtk_adjustment_get_upper (adj) -
+ gtk_adjustment_get_page_size (adj));
+ portion = min ((int)value, whole);
+ bar->dragging = portion;
+ }
+ else
+ {
+ part = scroll_bar_handle;
+ whole = gtk_adjustment_get_upper (adj) -
+ gtk_adjustment_get_page_size (adj);
+ portion = min ((int)value, whole);
+ bar->dragging = portion;
+ }
+ }
break;
case GTK_SCROLL_STEP_BACKWARD:
- part = scroll_bar_up_arrow;
+ part = (bar->horizontal
+ ? scroll_bar_left_arrow : scroll_bar_up_arrow);
bar->dragging = -1;
break;
case GTK_SCROLL_STEP_FORWARD:
- part = scroll_bar_down_arrow;
+ part = (bar->horizontal
+ ? scroll_bar_right_arrow : scroll_bar_down_arrow);
bar->dragging = -1;
break;
case GTK_SCROLL_PAGE_BACKWARD:
- part = scroll_bar_above_handle;
+ part = (bar->horizontal
+ ? scroll_bar_before_handle : scroll_bar_above_handle);
bar->dragging = -1;
break;
case GTK_SCROLL_PAGE_FORWARD:
- part = scroll_bar_below_handle;
+ part = (bar->horizontal
+ ? scroll_bar_after_handle : scroll_bar_below_handle);
bar->dragging = -1;
break;
}
- if (part >= 0)
+ if (part != scroll_bar_nowhere)
{
window_being_scrolled = bar->window;
- x_send_scroll_bar_event (bar->window, part, portion, whole);
+ x_send_scroll_bar_event (bar->window, part, portion, whole,
+ bar->horizontal);
}
return FALSE;
if (WINDOWP (window_being_scrolled))
{
x_send_scroll_bar_event (window_being_scrolled,
- scroll_bar_end_scroll, 0, 0);
+ scroll_bar_end_scroll, 0, 0, bar->horizontal);
window_being_scrolled = Qnil;
}
float *top_addr = call_data;
float top = *top_addr;
float shown;
- int whole, portion, height;
+ int whole, portion, height, width;
enum scroll_bar_part part;
+ bool horizontal = bar->horizontal;
- /* Get the size of the thumb, a value between 0 and 1. */
- block_input ();
- XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
- unblock_input ();
- whole = 10000000;
- portion = shown < 1 ? top * whole : 0;
+ if (horizontal)
+ {
+ /* Get the size of the thumb, a value between 0 and 1. */
+ block_input ();
+ XtVaGetValues (widget, XtNshown, &shown, XtNwidth, &width, NULL);
+ unblock_input ();
+
+ if (shown < 1)
+ {
+ whole = bar->whole - (shown * bar->whole);
+ portion = min (top * bar->whole, whole);
+ }
+ else
+ {
+ whole = bar->whole;
+ portion = 0;
+ }
- if (shown < 1 && (eabs (top + shown - 1) < 1.0f / height))
- /* Some derivatives of Xaw refuse to shrink the thumb when you reach
- the bottom, so we force the scrolling whenever we see that we're
- too close to the bottom (in x_set_toolkit_scroll_bar_thumb
- we try to ensure that we always stay two pixels away from the
- bottom). */
- part = scroll_bar_down_arrow;
+ part = scroll_bar_horizontal_handle;
+ }
else
- part = scroll_bar_handle;
+ {
+ /* Get the size of the thumb, a value between 0 and 1. */
+ block_input ();
+ XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
+ unblock_input ();
+
+ whole = 10000000;
+ portion = shown < 1 ? top * whole : 0;
+
+ if (shown < 1 && (eabs (top + shown - 1) < 1.0f / height))
+ /* Some derivatives of Xaw refuse to shrink the thumb when you reach
+ the bottom, so we force the scrolling whenever we see that we're
+ too close to the bottom (in x_set_toolkit_scroll_bar_thumb
+ we try to ensure that we always stay two pixels away from the
+ bottom). */
+ part = scroll_bar_down_arrow;
+ else
+ part = scroll_bar_handle;
+ }
window_being_scrolled = bar->window;
bar->dragging = portion;
bar->last_seen_part = part;
- x_send_scroll_bar_event (bar->window, part, portion, whole);
+ x_send_scroll_bar_event (bar->window, part, portion, whole, bar->horizontal);
}
struct scroll_bar *bar = client_data;
/* The position really is stored cast to a pointer. */
int position = (intptr_t) call_data;
- Dimension height;
+ Dimension height, width;
enum scroll_bar_part part;
- /* Get the height of the scroll bar. */
- block_input ();
- XtVaGetValues (widget, XtNheight, &height, NULL);
- unblock_input ();
+ if (bar->horizontal)
+ {
+ /* Get the width of the scroll bar. */
+ block_input ();
+ XtVaGetValues (widget, XtNwidth, &width, NULL);
+ unblock_input ();
+
+ if (eabs (position) >= width)
+ part = (position < 0) ? scroll_bar_before_handle : scroll_bar_after_handle;
- if (eabs (position) >= height)
- part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
+ /* If Xaw3d was compiled with ARROW_SCROLLBAR,
+ it maps line-movement to call_data = max(5, height/20). */
+ else if (xaw3d_arrow_scroll && eabs (position) <= max (5, width / 20))
+ part = (position < 0) ? scroll_bar_left_arrow : scroll_bar_right_arrow;
+ else
+ part = scroll_bar_move_ratio;
- /* If Xaw3d was compiled with ARROW_SCROLLBAR,
- it maps line-movement to call_data = max(5, height/20). */
- else if (xaw3d_arrow_scroll && eabs (position) <= max (5, height / 20))
- part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
+ window_being_scrolled = bar->window;
+ bar->dragging = -1;
+ bar->last_seen_part = part;
+ x_send_scroll_bar_event (bar->window, part, position, width,
+ bar->horizontal);
+ }
else
- part = scroll_bar_move_ratio;
+ {
- window_being_scrolled = bar->window;
- bar->dragging = -1;
- bar->last_seen_part = part;
- x_send_scroll_bar_event (bar->window, part, position, height);
+ /* Get the height of the scroll bar. */
+ block_input ();
+ XtVaGetValues (widget, XtNheight, &height, NULL);
+ unblock_input ();
+
+ if (eabs (position) >= height)
+ part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
+
+ /* If Xaw3d was compiled with ARROW_SCROLLBAR,
+ it maps line-movement to call_data = max(5, height/20). */
+ else if (xaw3d_arrow_scroll && eabs (position) <= max (5, height / 20))
+ part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
+ else
+ part = scroll_bar_move_ratio;
+
+ window_being_scrolled = bar->window;
+ bar->dragging = -1;
+ bar->last_seen_part = part;
+ x_send_scroll_bar_event (bar->window, part, position, height,
+ bar->horizontal);
+ }
}
#endif /* not USE_GTK and not USE_MOTIF */
#define SCROLL_BAR_NAME "verticalScrollBar"
+#define SCROLL_BAR_HORIZONTAL_NAME "horizontalScrollBar"
/* Create the widget for scroll bar BAR on frame F. Record the widget
and X window of the scroll bar in BAR. */
unblock_input ();
}
+static void
+x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
+{
+ const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME;
+
+ block_input ();
+ xg_create_horizontal_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
+ G_CALLBACK (xg_end_scroll_callback),
+ scroll_bar_name);
+ unblock_input ();
+}
+
#else /* not USE_GTK */
static void
SET_SCROLL_BAR_X_WIDGET (bar, widget);
xwindow = XtWindow (widget);
bar->x_window = xwindow;
+ bar->whole = 1;
+ bar->horizontal = false;
unblock_input ();
}
-#endif /* not USE_GTK */
-
-
-/* Set the thumb size and position of scroll bar BAR. We are currently
- displaying PORTION out of a whole WHOLE, and our position POSITION. */
-
-#ifdef USE_GTK
-static void
-x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole)
-{
- xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
-}
-#else /* not USE_GTK */
static void
-x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position,
- int whole)
+x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
{
- struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
- Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
- float top, shown;
+ Window xwindow;
+ Widget widget;
+ Arg av[20];
+ int ac = 0;
+ const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME;
+ unsigned long pixel;
block_input ();
#ifdef USE_MOTIF
+ /* Set resources. Create the widget. */
+ XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
+ XtSetArg (av[ac], XmNminimum, 0); ++ac;
+ XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
+ XtSetArg (av[ac], XmNorientation, XmHORIZONTAL); ++ac;
+ XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_RIGHT), ++ac;
+ XtSetArg (av[ac], XmNincrement, 1); ++ac;
+ XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
- if (scroll_bar_adjust_thumb_portion_p)
+ pixel = f->output_data.x->scroll_bar_foreground_pixel;
+ if (pixel != -1)
{
- /* We use an estimate of 30 chars per line rather than the real
- `portion' value. This has the disadvantage that the thumb size
- is not very representative, but it makes our life a lot easier.
- Otherwise, we have to constantly adjust the thumb size, which
- we can't always do quickly enough: while dragging, the size of
- the thumb might prevent the user from dragging the thumb all the
- way to the end. but Motif and some versions of Xaw3d don't allow
- updating the thumb size while dragging. Also, even if we can update
- its size, the update will often happen too late.
- If you don't believe it, check out revision 1.650 of xterm.c to see
- what hoops we were going through and the still poor behavior we got. */
- portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
- /* When the thumb is at the bottom, position == whole.
- So we need to increase `whole' to make space for the thumb. */
- whole += portion;
+ XtSetArg (av[ac], XmNforeground, pixel);
+ ++ac;
}
- if (whole <= 0)
- top = 0, shown = 1;
- else
+ pixel = f->output_data.x->scroll_bar_background_pixel;
+ if (pixel != -1)
{
- top = (float) position / whole;
- shown = (float) portion / whole;
+ XtSetArg (av[ac], XmNbackground, pixel);
+ ++ac;
+ }
+
+ widget = XmCreateScrollBar (f->output_data.x->edit_widget,
+ (char *) scroll_bar_name, av, ac);
+
+ /* Add one callback for everything that can happen. */
+ XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
+ (XtPointer) bar);
+
+ /* Realize the widget. Only after that is the X window created. */
+ XtRealizeWidget (widget);
+
+ /* Set the cursor to an arrow. I didn't find a resource to do that.
+ And I'm wondering why it hasn't an arrow cursor by default. */
+ XDefineCursor (XtDisplay (widget), XtWindow (widget),
+ f->output_data.x->nontext_cursor);
+
+#else /* !USE_MOTIF i.e. use Xaw */
+
+ /* Set resources. Create the widget. The background of the
+ Xaw3d scroll bar widget is a little bit light for my taste.
+ We don't alter it here to let users change it according
+ to their taste with `emacs*verticalScrollBar.background: xxx'. */
+ XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
+ XtSetArg (av[ac], XtNorientation, XtorientHorizontal); ++ac;
+ /* For smoother scrolling with Xaw3d -sm */
+ /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
+
+ pixel = f->output_data.x->scroll_bar_foreground_pixel;
+ if (pixel != -1)
+ {
+ XtSetArg (av[ac], XtNforeground, pixel);
+ ++ac;
+ }
+
+ pixel = f->output_data.x->scroll_bar_background_pixel;
+ if (pixel != -1)
+ {
+ XtSetArg (av[ac], XtNbackground, pixel);
+ ++ac;
+ }
+
+ /* Top/bottom shadow colors. */
+
+ /* Allocate them, if necessary. */
+ if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
+ {
+ pixel = f->output_data.x->scroll_bar_background_pixel;
+ if (pixel != -1)
+ {
+ if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
+ FRAME_X_COLORMAP (f),
+ &pixel, 1.2, 0x8000))
+ pixel = -1;
+ f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
+ }
+ }
+ if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
+ {
+ pixel = f->output_data.x->scroll_bar_background_pixel;
+ if (pixel != -1)
+ {
+ if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
+ FRAME_X_COLORMAP (f),
+ &pixel, 0.6, 0x4000))
+ pixel = -1;
+ f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
+ }
+ }
+
+#ifdef XtNbeNiceToColormap
+ /* Tell the toolkit about them. */
+ if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
+ || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
+ /* We tried to allocate a color for the top/bottom shadow, and
+ failed, so tell Xaw3d to use dithering instead. */
+ /* But only if we have a small colormap. Xaw3d can allocate nice
+ colors itself. */
+ {
+ XtSetArg (av[ac], XtNbeNiceToColormap,
+ DefaultDepthOfScreen (FRAME_X_SCREEN (f)) < 16);
+ ++ac;
+ }
+ else
+ /* Tell what colors Xaw3d should use for the top/bottom shadow, to
+ be more consistent with other emacs 3d colors, and since Xaw3d is
+ not good at dealing with allocation failure. */
+ {
+ /* This tells Xaw3d to use real colors instead of dithering for
+ the shadows. */
+ XtSetArg (av[ac], XtNbeNiceToColormap, False);
+ ++ac;
+
+ /* Specify the colors. */
+ pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
+ if (pixel != -1)
+ {
+ XtSetArg (av[ac], XtNtopShadowPixel, pixel);
+ ++ac;
+ }
+ pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
+ if (pixel != -1)
+ {
+ XtSetArg (av[ac], XtNbottomShadowPixel, pixel);
+ ++ac;
+ }
+ }
+#endif
+
+ widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
+ f->output_data.x->edit_widget, av, ac);
+
+ {
+ char const *initial = "";
+ char const *val = initial;
+ XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
+#ifdef XtNarrowScrollbars
+ XtNarrowScrollbars, (XtPointer) &xaw3d_arrow_scroll,
+#endif
+ XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
+ if (xaw3d_arrow_scroll || val == initial)
+ { /* ARROW_SCROLL */
+ xaw3d_arrow_scroll = True;
+ /* Isn't that just a personal preference ? --Stef */
+ XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
+ }
+ }
+
+ /* Define callbacks. */
+ XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
+ XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
+ (XtPointer) bar);
+
+ /* Realize the widget. Only after that is the X window created. */
+ XtRealizeWidget (widget);
+
+#endif /* !USE_MOTIF */
+
+ /* Install an action hook that lets us detect when the user
+ finishes interacting with a scroll bar. */
+ if (horizontal_action_hook_id == 0)
+ horizontal_action_hook_id
+ = XtAppAddActionHook (Xt_app_con, xt_horizontal_action_hook, 0);
+
+ /* Remember X window and widget in the scroll bar vector. */
+ SET_SCROLL_BAR_X_WIDGET (bar, widget);
+ xwindow = XtWindow (widget);
+ bar->x_window = xwindow;
+ bar->whole = 1;
+ bar->horizontal = true;
+
+ unblock_input ();
+}
+#endif /* not USE_GTK */
+
+
+/* Set the thumb size and position of scroll bar BAR. We are currently
+ displaying PORTION out of a whole WHOLE, and our position POSITION. */
+
+#ifdef USE_GTK
+static void
+x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole)
+{
+ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
+}
+
+static void
+x_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole)
+{
+ xg_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
+}
+
+#else /* not USE_GTK */
+static void
+x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position,
+ int whole)
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
+ float top, shown;
+
+ block_input ();
+
+#ifdef USE_MOTIF
+
+ if (scroll_bar_adjust_thumb_portion_p)
+ {
+ /* We use an estimate of 30 chars per line rather than the real
+ `portion' value. This has the disadvantage that the thumb size
+ is not very representative, but it makes our life a lot easier.
+ Otherwise, we have to constantly adjust the thumb size, which
+ we can't always do quickly enough: while dragging, the size of
+ the thumb might prevent the user from dragging the thumb all the
+ way to the end. but Motif and some versions of Xaw3d don't allow
+ updating the thumb size while dragging. Also, even if we can update
+ its size, the update will often happen too late.
+ If you don't believe it, check out revision 1.650 of xterm.c to see
+ what hoops we were going through and the still poor behavior we got. */
+ portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 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
+ {
+ top = (float) position / whole;
+ shown = (float) portion / whole;
}
if (bar->dragging == -1)
unblock_input ();
}
+
+static void
+x_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position,
+ int whole)
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
+ float top, shown;
+
+ block_input ();
+
+#ifdef USE_MOTIF
+ bar->whole = whole;
+ shown = (float) portion / whole;
+ top = (float) position / (whole - portion);
+ {
+ int size = clip_to_bounds (1, shown * XM_SB_MAX, XM_SB_MAX);
+ int value = clip_to_bounds (0, top * (XM_SB_MAX - size), XM_SB_MAX - size);
+
+ XmScrollBarSetValues (widget, value, size, 0, 0, False);
+ }
+#else /* !USE_MOTIF i.e. use Xaw */
+ bar->whole = whole;
+ if (whole == 0)
+ top = 0, shown = 1;
+ else
+ {
+ top = (float) position / whole;
+ shown = (float) portion / whole;
+ }
+
+ {
+ float old_top, old_shown;
+ Dimension height;
+ XtVaGetValues (widget,
+ XtNtopOfThumb, &old_top,
+ XtNshown, &old_shown,
+ XtNheight, &height,
+ NULL);
+
+#if false
+ /* Massage the top+shown values. */
+ if (bar->dragging == -1 || bar->last_seen_part == scroll_bar_down_arrow)
+ top = max (0, min (1, top));
+ else
+ top = old_top;
+#if ! defined (HAVE_XAW3D)
+ /* With Xaw, 'top' values too closer to 1.0 may
+ cause the thumb to disappear. Fix that. */
+ top = min (top, 0.99f);
+#endif
+ /* Keep two pixels available for moving the thumb down. */
+ shown = max (0, min (1 - top - (2.0f / height), shown));
+#if ! defined (HAVE_XAW3D)
+ /* Likewise with too small 'shown'. */
+ shown = max (shown, 0.01f);
+#endif
+#endif
+
+ /* If the call to XawScrollbarSetThumb below doesn't seem to
+ work, check that 'NARROWPROTO' is defined in src/config.h.
+ If this is not so, most likely you need to fix configure. */
+ XawScrollbarSetThumb (widget, top, shown);
+#if false
+ if (top != old_top || shown != old_shown)
+ {
+ if (bar->dragging == -1)
+ XawScrollbarSetThumb (widget, top, shown);
+ else
+ {
+ /* Try to make the scrolling a tad smoother. */
+ if (!xaw3d_pick_top)
+ shown = min (shown, old_shown);
+
+ XawScrollbarSetThumb (widget, top, shown);
+ }
+ }
+#endif
+ }
+#endif /* !USE_MOTIF */
+
+ unblock_input ();
+}
#endif /* not USE_GTK */
#endif /* USE_TOOLKIT_SCROLL_BARS */
scroll bar. */
static struct scroll_bar *
-x_scroll_bar_create (struct window *w, int top, int left, int width, int height)
+x_scroll_bar_create (struct window *w, int top, int left,
+ int width, int height, bool horizontal)
{
struct frame *f = XFRAME (w->frame);
struct scroll_bar *bar
block_input ();
#ifdef USE_TOOLKIT_SCROLL_BARS
- x_create_toolkit_scroll_bar (f, bar);
+ if (horizontal)
+ x_create_horizontal_toolkit_scroll_bar (f, bar);
+ else
+ x_create_toolkit_scroll_bar (f, bar);
#else /* not USE_TOOLKIT_SCROLL_BARS */
{
XSetWindowAttributes a;
bar->start = 0;
bar->end = 0;
bar->dragging = -1;
+ bar->horizontal = horizontal;
#if defined (USE_TOOLKIT_SCROLL_BARS) && defined (USE_LUCID)
bar->last_seen_part = scroll_bar_nowhere;
#endif
#ifdef USE_TOOLKIT_SCROLL_BARS
{
#ifdef USE_GTK
- xg_update_scrollbar_pos (f, bar->x_window, top,
- left,width, max (height, 1));
+ if (horizontal)
+ xg_update_horizontal_scrollbar_pos (f, bar->x_window, top,
+ left, width, max (height, 1));
+ else
+ xg_update_scrollbar_pos (f, bar->x_window, top,
+ left, width, max (height, 1));
#else /* not USE_GTK */
Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
XtConfigureWidget (scroll_bar, left, top, width, max (height, 1), 0);
/* Draw BAR's handle in the proper position.
If the handle is already drawn from START to END, don't bother
- redrawing it, unless REBUILD is non-zero; in that case, always
+ redrawing it, unless REBUILD; in that case, always
redraw it. (REBUILD is handy for drawing the handle after expose
events.)
to move to the very end of the buffer. */
static void
-x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end, int rebuild)
+x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
+ bool rebuild)
{
bool dragging = bar->dragging != -1;
Window w = bar->x_window;
/* Draw the empty space above the handle. Note that we can't clear
zero-height areas; that means "clear to end of window." */
- if (start > 0)
+ if ((inside_width > 0) && (start > 0))
x_clear_area (FRAME_X_DISPLAY (f), w,
VERTICAL_SCROLL_BAR_LEFT_BORDER,
VERTICAL_SCROLL_BAR_TOP_BORDER,
/* Draw the empty space below the handle. Note that we can't
clear zero-height areas; that means "clear to end of window." */
- if (end < inside_height)
+ if ((inside_width > 0) && (end < inside_height))
x_clear_area (FRAME_X_DISPLAY (f), w,
VERTICAL_SCROLL_BAR_LEFT_BORDER,
VERTICAL_SCROLL_BAR_TOP_BORDER + end,
#endif
/* Dissociate this scroll bar from its window. */
- wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
+ if (bar->horizontal)
+ wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
+ else
+ wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
unblock_input ();
}
window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
top = window_y;
height = window_height;
-
- /* Compute the left edge and the width of the scroll bar area. */
left = WINDOW_SCROLL_BAR_AREA_X (w);
width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
unblock_input ();
}
- bar = x_scroll_bar_create (w, top, left, width, max (height, 1));
+ bar = x_scroll_bar_create (w, top, left, width, max (height, 1), false);
}
else
{
int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
if (whole == 0)
- x_scroll_bar_set_handle (bar, 0, top_range, 0);
+ x_scroll_bar_set_handle (bar, 0, top_range, false);
else
{
int start = ((double) position * top_range) / whole;
int end = ((double) (position + portion) * top_range) / whole;
- x_scroll_bar_set_handle (bar, start, end, 0);
+ x_scroll_bar_set_handle (bar, start, end, false);
}
}
#endif /* not USE_TOOLKIT_SCROLL_BARS */
}
+static void
+XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int position)
+{
+ struct frame *f = XFRAME (w->frame);
+ Lisp_Object barobj;
+ struct scroll_bar *bar;
+ int top, height, left, width;
+ int window_x, window_width;
+ int pixel_width = WINDOW_PIXEL_WIDTH (w);
+
+ /* Get window dimensions. */
+ window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
+ left = window_x;
+ width = window_width;
+ top = WINDOW_SCROLL_BAR_AREA_Y (w);
+ height = WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
+
+ /* Does the scroll bar exist yet? */
+ if (NILP (w->horizontal_scroll_bar))
+ {
+ if (width > 0 && height > 0)
+ {
+ block_input ();
+
+ /* Clear also part between window_width and
+ WINDOW_PIXEL_WIDTH. */
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ left, top, pixel_width, height);
+ unblock_input ();
+ }
+
+ bar = x_scroll_bar_create (w, top, left, width, height, true);
+ }
+ else
+ {
+ /* It may just need to be moved and resized. */
+ unsigned int mask = 0;
+
+ bar = XSCROLL_BAR (w->horizontal_scroll_bar);
+
+ block_input ();
+
+ if (left != bar->left)
+ mask |= CWX;
+ if (top != bar->top)
+ mask |= CWY;
+ if (width != bar->width)
+ mask |= CWWidth;
+ if (height != bar->height)
+ mask |= CWHeight;
+
+#ifdef USE_TOOLKIT_SCROLL_BARS
+ /* Move/size the scroll bar widget. */
+ if (mask)
+ {
+ /* Since toolkit scroll bars are smaller than the space reserved
+ for them on the frame, we have to clear "under" them. */
+ if (width > 0 && height > 0)
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ WINDOW_LEFT_EDGE_X (w), top,
+ pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w), height);
+#ifdef USE_GTK
+ xg_update_horizontal_scrollbar_pos (f, bar->x_window, top, left,
+ width, height);
+#else /* not USE_GTK */
+ XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
+ left, top, width, height, 0);
+#endif /* not USE_GTK */
+ }
+#else /* not USE_TOOLKIT_SCROLL_BARS */
+
+ /* Clear areas not covered by the scroll bar because it's not as
+ wide as the area reserved for it. This makes sure a
+ previous mode line display is cleared after C-x 2 C-x 1, for
+ example. */
+ {
+ int area_height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
+ int rest = area_height - height;
+ if (rest > 0 && width > 0)
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ left, top, width, rest);
+ }
+
+ /* Move/size the scroll bar window. */
+ if (mask)
+ {
+ XWindowChanges wc;
+
+ wc.x = left;
+ wc.y = top;
+ wc.width = width;
+ wc.height = height;
+ XConfigureWindow (FRAME_X_DISPLAY (f), bar->x_window,
+ mask, &wc);
+ }
+
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
+
+ /* Remember new settings. */
+ bar->left = left;
+ bar->top = top;
+ bar->width = width;
+ bar->height = height;
+
+ unblock_input ();
+ }
+
+#ifdef USE_TOOLKIT_SCROLL_BARS
+ x_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
+#else /* not USE_TOOLKIT_SCROLL_BARS */
+ /* Set the scroll bar's current state, unless we're currently being
+ dragged. */
+ if (bar->dragging == -1)
+ {
+ int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, width);
+
+ if (whole == 0)
+ x_scroll_bar_set_handle (bar, 0, left_range, false);
+ else
+ {
+ int start = ((double) position * left_range) / whole;
+ int end = ((double) (position + portion) * left_range) / whole;
+ x_scroll_bar_set_handle (bar, start, end, false);
+ }
+ }
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
+
+ XSETVECTOR (barobj, bar);
+ wset_horizontal_scroll_bar (w, barobj);
+}
+
+
/* The following three hooks are used when we're doing a thorough
redisplay of the frame. We don't explicitly know which scroll bars
are going to be deleted, because keeping track of when windows go
static void
XTcondemn_scroll_bars (struct frame *frame)
{
- /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
- while (! NILP (FRAME_SCROLL_BARS (frame)))
+ if (!NILP (FRAME_SCROLL_BARS (frame)))
{
- Lisp_Object bar;
- bar = FRAME_SCROLL_BARS (frame);
- fset_scroll_bars (frame, XSCROLL_BAR (bar)->next);
- XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
- XSCROLL_BAR (bar)->prev = Qnil;
- if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
- XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
- fset_condemned_scroll_bars (frame, bar);
+ if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
+ {
+ /* Prepend scrollbars to already condemned ones. */
+ Lisp_Object last = FRAME_SCROLL_BARS (frame);
+
+ while (!NILP (XSCROLL_BAR (last)->next))
+ last = XSCROLL_BAR (last)->next;
+
+ XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
+ XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
+ }
+
+ fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
+ fset_scroll_bars (frame, Qnil);
}
}
Note that WINDOW isn't necessarily condemned at all. */
static void
-XTredeem_scroll_bar (struct window *window)
+XTredeem_scroll_bar (struct window *w)
{
struct scroll_bar *bar;
- struct frame *f;
Lisp_Object barobj;
+ struct frame *f;
/* We can't redeem this window's scroll bar if it doesn't have one. */
- if (NILP (window->vertical_scroll_bar))
+ if (NILP (w->vertical_scroll_bar) && NILP (w->horizontal_scroll_bar))
emacs_abort ();
- bar = XSCROLL_BAR (window->vertical_scroll_bar);
-
- /* Unlink it from the condemned list. */
- f = XFRAME (WINDOW_FRAME (window));
- if (NILP (bar->prev))
+ if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
{
- /* If the prev pointer is nil, it must be the first in one of
- the lists. */
- if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
- /* It's not condemned. Everything's fine. */
- return;
- else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
- window->vertical_scroll_bar))
- fset_condemned_scroll_bars (f, bar->next);
+ bar = XSCROLL_BAR (w->vertical_scroll_bar);
+ /* Unlink it from the condemned list. */
+ f = XFRAME (WINDOW_FRAME (w));
+ if (NILP (bar->prev))
+ {
+ /* If the prev pointer is nil, it must be the first in one of
+ the lists. */
+ if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
+ /* It's not condemned. Everything's fine. */
+ goto horizontal;
+ else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
+ w->vertical_scroll_bar))
+ fset_condemned_scroll_bars (f, bar->next);
+ else
+ /* If its prev pointer is nil, it must be at the front of
+ one or the other! */
+ emacs_abort ();
+ }
else
- /* If its prev pointer is nil, it must be at the front of
- one or the other! */
- emacs_abort ();
+ XSCROLL_BAR (bar->prev)->next = bar->next;
+
+ if (! NILP (bar->next))
+ XSCROLL_BAR (bar->next)->prev = bar->prev;
+
+ bar->next = FRAME_SCROLL_BARS (f);
+ bar->prev = Qnil;
+ XSETVECTOR (barobj, bar);
+ fset_scroll_bars (f, barobj);
+ if (! NILP (bar->next))
+ XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
}
- else
- XSCROLL_BAR (bar->prev)->next = bar->next;
- if (! NILP (bar->next))
- XSCROLL_BAR (bar->next)->prev = bar->prev;
+ horizontal:
+ if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
+ {
+ bar = XSCROLL_BAR (w->horizontal_scroll_bar);
+ /* Unlink it from the condemned list. */
+ f = XFRAME (WINDOW_FRAME (w));
+ if (NILP (bar->prev))
+ {
+ /* If the prev pointer is nil, it must be the first in one of
+ the lists. */
+ if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
+ /* It's not condemned. Everything's fine. */
+ return;
+ else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
+ w->horizontal_scroll_bar))
+ fset_condemned_scroll_bars (f, bar->next);
+ else
+ /* If its prev pointer is nil, it must be at the front of
+ one or the other! */
+ emacs_abort ();
+ }
+ else
+ XSCROLL_BAR (bar->prev)->next = bar->next;
- bar->next = FRAME_SCROLL_BARS (f);
- bar->prev = Qnil;
- XSETVECTOR (barobj, bar);
- fset_scroll_bars (f, barobj);
- if (! NILP (bar->next))
- XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+ if (! NILP (bar->next))
+ XSCROLL_BAR (bar->next)->prev = bar->prev;
+
+ bar->next = FRAME_SCROLL_BARS (f);
+ bar->prev = Qnil;
+ XSETVECTOR (barobj, bar);
+ fset_scroll_bars (f, barobj);
+ if (! NILP (bar->next))
+ XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+ }
}
/* Remove all scroll bars on FRAME that haven't been saved since the
block_input ();
- x_scroll_bar_set_handle (bar, bar->start, bar->end, 1);
+ x_scroll_bar_set_handle (bar, bar->start, bar->end, true);
/* Switch to scroll bar foreground color. */
if (f->output_data.x->scroll_bar_foreground_pixel != -1)
if (! WINDOWP (bar->window))
emacs_abort ();
- emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
+ emacs_event->kind = (bar->horizontal
+ ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT
+ : SCROLL_BAR_CLICK_EVENT);
emacs_event->code = event->xbutton.button - Button1;
emacs_event->modifiers
= (x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO
emacs_event->frame_or_window = bar->window;
emacs_event->arg = Qnil;
emacs_event->timestamp = event->xbutton.time;
- {
- int top_range
- = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
- int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
+ if (bar->horizontal)
+ {
+ int left_range
+ = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
+ int x = event->xbutton.x - HORIZONTAL_SCROLL_BAR_LEFT_BORDER;
- if (y < 0) y = 0;
- if (y > top_range) y = top_range;
+ if (x < 0) x = 0;
+ if (x > left_range) x = left_range;
- if (y < bar->start)
- emacs_event->part = scroll_bar_above_handle;
- else if (y < bar->end + VERTICAL_SCROLL_BAR_MIN_HANDLE)
- emacs_event->part = scroll_bar_handle;
- else
- emacs_event->part = scroll_bar_below_handle;
+ if (x < bar->start)
+ emacs_event->part = scroll_bar_before_handle;
+ else if (x < bar->end + HORIZONTAL_SCROLL_BAR_MIN_HANDLE)
+ emacs_event->part = scroll_bar_horizontal_handle;
+ else
+ emacs_event->part = scroll_bar_after_handle;
#ifndef USE_TOOLKIT_SCROLL_BARS
- /* If the user has released the handle, set it to its final position. */
- if (event->type == ButtonRelease && bar->dragging != -1)
- {
- int new_start = y - bar->dragging;
- int new_end = new_start + bar->end - bar->start;
+ /* If the user has released the handle, set it to its final position. */
+ if (event->type == ButtonRelease && bar->dragging != -1)
+ {
+ int new_start = - bar->dragging;
+ int new_end = new_start + bar->end - bar->start;
- x_scroll_bar_set_handle (bar, new_start, new_end, 0);
- bar->dragging = -1;
- }
+ x_scroll_bar_set_handle (bar, new_start, new_end, false);
+ bar->dragging = -1;
+ }
#endif
- XSETINT (emacs_event->x, y);
- XSETINT (emacs_event->y, top_range);
- }
+ XSETINT (emacs_event->x, left_range);
+ XSETINT (emacs_event->y, x);
+ }
+ else
+ {
+ int top_range
+ = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
+ int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
+
+ if (y < 0) y = 0;
+ if (y > top_range) y = top_range;
+
+ if (y < bar->start)
+ emacs_event->part = scroll_bar_above_handle;
+ else if (y < bar->end + VERTICAL_SCROLL_BAR_MIN_HANDLE)
+ emacs_event->part = scroll_bar_handle;
+ else
+ emacs_event->part = scroll_bar_below_handle;
+
+#ifndef USE_TOOLKIT_SCROLL_BARS
+ /* If the user has released the handle, set it to its final position. */
+ if (event->type == ButtonRelease && bar->dragging != -1)
+ {
+ int new_start = y - bar->dragging;
+ int new_end = new_start + bar->end - bar->start;
+
+ x_scroll_bar_set_handle (bar, new_start, new_end, false);
+ bar->dragging = -1;
+ }
+#endif
+
+ XSETINT (emacs_event->x, y);
+ XSETINT (emacs_event->y, top_range);
+ }
}
#ifndef USE_TOOLKIT_SCROLL_BARS
dpyinfo->last_mouse_movement_time = event->time;
dpyinfo->last_mouse_scroll_bar = bar;
- f->mouse_moved = 1;
+ f->mouse_moved = true;
/* If we're dragging the bar, display it. */
if (bar->dragging != -1)
{
int new_end = new_start + bar->end - bar->start;
- x_scroll_bar_set_handle (bar, new_start, new_end, 0);
+ x_scroll_bar_set_handle (bar, new_start, new_end, false);
}
}
}
XSETINT (*x, win_y);
XSETINT (*y, top_range);
- f->mouse_moved = 0;
+ f->mouse_moved = false;
+ dpyinfo->last_mouse_scroll_bar = NULL;
+ *timestamp = dpyinfo->last_mouse_movement_time;
+ }
+
+ unblock_input ();
+}
+
+
+/* Return information to the user about the current position of the mouse
+ on the scroll bar. */
+
+static void
+x_horizontal_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
+ enum scroll_bar_part *part, Lisp_Object *x,
+ Lisp_Object *y, Time *timestamp)
+{
+ struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
+ struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
+ Window w = bar->x_window;
+ struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ int win_x, win_y;
+ Window dummy_window;
+ int dummy_coord;
+ unsigned int dummy_mask;
+
+ block_input ();
+
+ /* Get the mouse's position relative to the scroll bar window, and
+ report that. */
+ if (XQueryPointer (FRAME_X_DISPLAY (f), w,
+
+ /* Root, child, root x and root y. */
+ &dummy_window, &dummy_window,
+ &dummy_coord, &dummy_coord,
+
+ /* Position relative to scroll bar. */
+ &win_x, &win_y,
+
+ /* Mouse buttons and modifier keys. */
+ &dummy_mask))
+ {
+ int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
+
+ win_x -= HORIZONTAL_SCROLL_BAR_LEFT_BORDER;
+
+ if (bar->dragging != -1)
+ win_x -= bar->dragging;
+
+ if (win_x < 0)
+ win_x = 0;
+ if (win_x > left_range)
+ win_x = left_range;
+
+ *fp = f;
+ *bar_window = bar->window;
+
+ if (bar->dragging != -1)
+ *part = scroll_bar_horizontal_handle;
+ else if (win_x < bar->start)
+ *part = scroll_bar_before_handle;
+ else if (win_x < bar->end + HORIZONTAL_SCROLL_BAR_MIN_HANDLE)
+ *part = scroll_bar_handle;
+ else
+ *part = scroll_bar_after_handle;
+
+ XSETINT (*y, win_x);
+ XSETINT (*x, left_range);
+
+ f->mouse_moved = false;
dpyinfo->last_mouse_scroll_bar = NULL;
*timestamp = dpyinfo->last_mouse_movement_time;
}
static short temp_buffer[100];
#define STORE_KEYSYM_FOR_DEBUG(keysym) \
- if (temp_index == sizeof temp_buffer / sizeof (short)) \
+ if (temp_index == ARRAYELTS (temp_buffer)) \
temp_index = 0; \
temp_buffer[temp_index++] = (keysym)
enum xembed_message,
long detail, long data1, long data2);
+static void
+x_net_wm_state (struct frame *f, Window window)
+{
+ int value = FULLSCREEN_NONE;
+ Lisp_Object lval = Qnil;
+ bool sticky = false;
+
+ get_current_wm_state (f, window, &value, &sticky);
+
+ switch (value)
+ {
+ case FULLSCREEN_WIDTH:
+ lval = Qfullwidth;
+ break;
+ case FULLSCREEN_HEIGHT:
+ lval = Qfullheight;
+ break;
+ case FULLSCREEN_BOTH:
+ lval = Qfullboth;
+ break;
+ case FULLSCREEN_MAXIMIZED:
+ lval = Qmaximized;
+ break;
+ }
+
+ store_frame_param (f, Qfullscreen, lval);
+/** store_frame_param (f, Qsticky, sticky ? Qt : Qnil); **/
+}
+
/* Handles the XEvent EVENT on display DPYINFO.
*FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
if (f && FRAME_XIC (f))
XSetICFocus (FRAME_XIC (f));
#endif
-#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
+#if false
+ /* Emacs sets WM hints whose `input' field is `true'. This
instructs the WM to set the input focus automatically for
Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
x_uncatch_errors ();
}
/* Not certain about handling scroll bars here */
-#endif /* 0 */
+#endif
goto done;
}
*finish = X_EVENT_GOTO_OUT;
goto done;
}
+ else if (event->xclient.message_type == dpyinfo->Xatom_Horizontal_Scrollbar)
+ {
+ x_horizontal_scroll_bar_to_input_event (event, &inev.ie);
+ *finish = X_EVENT_GOTO_OUT;
+ goto done;
+ }
#endif /* USE_TOOLKIT_SCROLL_BARS */
/* XEmbed messages from the embedder (if any). */
break;
case SelectionNotify:
- dpyinfo->last_user_time = event->xselection.time;
+ x_display_set_last_user_time (dpyinfo, event->xselection.time);
#ifdef USE_X_TOOLKIT
if (! x_window_to_frame (dpyinfo, event->xselection.requestor))
goto OTHER;
break;
case SelectionClear: /* Someone has grabbed ownership. */
- dpyinfo->last_user_time = event->xselectionclear.time;
+ x_display_set_last_user_time (dpyinfo, event->xselectionclear.time);
#ifdef USE_X_TOOLKIT
if (! x_window_to_frame (dpyinfo, event->xselectionclear.window))
goto OTHER;
const XSelectionClearEvent *eventp = &event->xselectionclear;
inev.ie.kind = SELECTION_CLEAR_EVENT;
- SELECTION_EVENT_DISPLAY (&inev.sie) = eventp->display;
+ SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
}
break;
case SelectionRequest: /* Someone wants our selection. */
- dpyinfo->last_user_time = event->xselectionrequest.time;
+ x_display_set_last_user_time (dpyinfo, event->xselectionrequest.time);
#ifdef USE_X_TOOLKIT
if (!x_window_to_frame (dpyinfo, event->xselectionrequest.owner))
goto OTHER;
const XSelectionRequestEvent *eventp = &event->xselectionrequest;
inev.ie.kind = SELECTION_REQUEST_EVENT;
- SELECTION_EVENT_DISPLAY (&inev.sie) = eventp->display;
+ SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
SELECTION_EVENT_REQUESTOR (&inev.sie) = eventp->requestor;
SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
SELECTION_EVENT_TARGET (&inev.sie) = eventp->target;
break;
case PropertyNotify:
- dpyinfo->last_user_time = event->xproperty.time;
+ x_display_set_last_user_time (dpyinfo, event->xproperty.time);
f = x_top_window_to_frame (dpyinfo, event->xproperty.window);
if (f && event->xproperty.atom == dpyinfo->Xatom_net_wm_state)
- if (x_handle_net_wm_state (f, &event->xproperty)
- && FRAME_ICONIFIED_P (f)
- && f->output_data.x->net_wm_state_hidden_seen)
- {
- /* Gnome shell does not iconify us when C-z is pressed.
- It hides the frame. So if our state says we aren't
- hidden anymore, treat it as deiconified. */
- SET_FRAME_VISIBLE (f, 1);
- SET_FRAME_ICONIFIED (f, 0);
- f->output_data.x->has_been_visible = 1;
- f->output_data.x->net_wm_state_hidden_seen = 0;
- inev.ie.kind = DEICONIFY_EVENT;
- XSETFRAME (inev.ie.frame_or_window, f);
- }
+ {
+ bool not_hidden = x_handle_net_wm_state (f, &event->xproperty);
+ if (not_hidden && FRAME_ICONIFIED_P (f))
+ {
+ /* Gnome shell does not iconify us when C-z is pressed.
+ It hides the frame. So if our state says we aren't
+ hidden anymore, treat it as deiconified. */
+ SET_FRAME_VISIBLE (f, 1);
+ SET_FRAME_ICONIFIED (f, false);
+ f->output_data.x->has_been_visible = true;
+ inev.ie.kind = DEICONIFY_EVENT;
+ XSETFRAME (inev.ie.frame_or_window, f);
+ }
+ else if (! not_hidden && ! FRAME_ICONIFIED_P (f))
+ {
+ SET_FRAME_VISIBLE (f, 0);
+ SET_FRAME_ICONIFIED (f, true);
+ inev.ie.kind = ICONIFY_EVENT;
+ XSETFRAME (inev.ie.frame_or_window, f);
+ }
+ }
x_handle_property_notify (&event->xproperty);
xft_settings_event (dpyinfo, event);
if (!FRAME_VISIBLE_P (f))
{
SET_FRAME_VISIBLE (f, 1);
- SET_FRAME_ICONIFIED (f, 0);
- f->output_data.x->has_been_visible = 1;
+ SET_FRAME_ICONIFIED (f, false);
+ f->output_data.x->has_been_visible = true;
SET_FRAME_GARBAGED (f);
}
else
goto OTHER;
#else /* not USE_TOOLKIT_SCROLL_BARS */
bar = x_window_to_scroll_bar (event->xexpose.display,
- event->xexpose.window);
+ event->xexpose.window, 2);
if (bar)
x_scroll_bar_expose (bar, event);
and that way, we know the window is not iconified now. */
if (visible || FRAME_ICONIFIED_P (f))
{
- SET_FRAME_ICONIFIED (f, 1);
+ SET_FRAME_ICONIFIED (f, true);
inev.ie.kind = ICONIFY_EVENT;
XSETFRAME (inev.ie.frame_or_window, f);
}
x_check_fullscreen (f);
SET_FRAME_VISIBLE (f, 1);
- SET_FRAME_ICONIFIED (f, 0);
- f->output_data.x->has_been_visible = 1;
+ SET_FRAME_ICONIFIED (f, false);
+ f->output_data.x->has_been_visible = true;
if (iconified)
{
case KeyPress:
- dpyinfo->last_user_time = event->xkey.time;
+ x_display_set_last_user_time (dpyinfo, event->xkey.time);
ignore_next_mouse_click_timeout = 0;
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
|| !EQ (f->tool_bar_window, hlinfo->mouse_face_window)))
{
clear_mouse_face (hlinfo);
- hlinfo->mouse_face_hidden = 1;
+ hlinfo->mouse_face_hidden = true;
}
#endif
for (i = 0, nchars = 0; i < nbytes; i++)
{
- if (ASCII_BYTE_P (copy_bufptr[i]))
+ if (ASCII_CHAR_P (copy_bufptr[i]))
nchars++;
STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
}
which depends on which X*LookupString function
we used just above and the locale. */
setup_coding_system (coding_system, &coding);
- coding.src_multibyte = 0;
- coding.dst_multibyte = 1;
+ coding.src_multibyte = false;
+ coding.dst_multibyte = true;
/* The input is converted to events, thus we can't
handle composition. Anyway, there's no XIM that
gives us composition information. */
#endif
case KeyRelease:
- dpyinfo->last_user_time = event->xkey.time;
+ x_display_set_last_user_time (dpyinfo, event->xkey.time);
#ifdef HAVE_X_I18N
/* Don't dispatch this event since XtDispatchEvent calls
XFilterEvent, and two calls in a row may freeze the
#endif
case EnterNotify:
- dpyinfo->last_user_time = event->xcrossing.time;
+ x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
x_detect_focus_change (dpyinfo, any, event, &inev.ie);
f = any;
goto OTHER;
case LeaveNotify:
- dpyinfo->last_user_time = event->xcrossing.time;
+ x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
x_detect_focus_change (dpyinfo, any, event, &inev.ie);
f = x_top_window_to_frame (dpyinfo, event->xcrossing.window);
case MotionNotify:
{
- dpyinfo->last_user_time = event->xmotion.time;
+ x_display_set_last_user_time (dpyinfo, event->xmotion.time);
previous_help_echo_string = help_echo_string;
help_echo_string = Qnil;
if (hlinfo->mouse_face_hidden)
{
- hlinfo->mouse_face_hidden = 0;
+ hlinfo->mouse_face_hidden = false;
clear_mouse_face (hlinfo);
}
{
static Lisp_Object last_mouse_window;
Lisp_Object window = window_from_coordinates
- (f, event->xmotion.x, event->xmotion.y, 0, 0);
+ (f, event->xmotion.x, event->xmotion.y, 0, false);
/* Window will be selected only when it is not selected now and
last mouse movement event was not in it. Minibuffer window
#ifndef USE_TOOLKIT_SCROLL_BARS
struct scroll_bar *bar
= x_window_to_scroll_bar (event->xmotion.display,
- event->xmotion.window);
+ event->xmotion.window, 2);
if (bar)
x_scroll_bar_note_movement (bar, &event->xmotion);
#endif
if (f)
{
+ x_net_wm_state (f, event->xconfigure.window);
+
#ifndef USE_X_TOOLKIT
#ifndef USE_GTK
int width = FRAME_PIXEL_TO_TEXT_WIDTH (f, event->xconfigure.width);
|| event->xconfigure.width != FRAME_PIXEL_WIDTH (f)
|| event->xconfigure.height != FRAME_PIXEL_HEIGHT (f))
{
- change_frame_size (f, width, height, 0, 1, 0, 1);
+ change_frame_size (f, width, height, false, true, false, true);
x_clear_under_internal_border (f);
SET_FRAME_GARBAGED (f);
cancel_mouse_face (f);
}
-
-/** FRAME_PIXEL_WIDTH (f) = event->xconfigure.width; **/
-/** FRAME_PIXEL_HEIGHT (f) = event->xconfigure.height; **/
#endif /* not USE_GTK */
#endif
{
/* If we decide we want to generate an event to be seen
by the rest of Emacs, we put it here. */
- bool tool_bar_p = 0;
+ bool tool_bar_p = false;
memset (&compose_status, 0, sizeof (compose_status));
dpyinfo->last_mouse_glyph_frame = NULL;
- dpyinfo->last_user_time = event->xbutton.time;
+ x_display_set_last_user_time (dpyinfo, event->xbutton.time);
f = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
: x_window_to_frame (dpyinfo, event->xbutton.window));
int x = event->xbutton.x;
int y = event->xbutton.y;
- window = window_from_coordinates (f, x, y, 0, 1);
+ window = window_from_coordinates (f, x, y, 0, true);
tool_bar_p = EQ (window, f->tool_bar_window);
if (tool_bar_p && event->xbutton.button < 4)
{
struct scroll_bar *bar
= x_window_to_scroll_bar (event->xbutton.display,
- event->xbutton.window);
+ event->xbutton.window, 2);
#ifdef USE_TOOLKIT_SCROLL_BARS
/* Make the "Ctrl-Mouse-2 splits window" work for toolkit
{
dpyinfo->grabbed |= (1 << event->xbutton.button);
dpyinfo->last_mouse_frame = f;
-
- if (!tool_bar_p)
- last_tool_bar_item = -1;
+#if ! defined (USE_GTK)
+ if (f && !tool_bar_p)
+ f->last_tool_bar_item = -1;
+#endif /* not USE_GTK */
}
else
dpyinfo->grabbed &= ~(1 << event->xbutton.button);
any subsequent mouse-movement Emacs events should reflect
only motion after the ButtonPress/Release. */
if (f != 0)
- f->mouse_moved = 0;
+ f->mouse_moved = false;
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
f = x_menubar_window_to_frame (dpyinfo, event);
&& event->xbutton.x >= 0
&& event->xbutton.x < FRAME_PIXEL_WIDTH (f)
&& event->xbutton.y >= 0
- && event->xbutton.y < f->output_data.x->menubar_height
+ && event->xbutton.y < FRAME_MENUBAR_HEIGHT (f)
&& event->xbutton.same_screen)
{
if (!f->output_data.x->saved_menu_event)
if (do_help > 0)
{
- any_help_event_p = 1;
+ any_help_event_p = true;
gen_help_event (help_echo_string, frame, help_echo_window,
help_echo_object, help_echo_pos);
}
XTread_socket (struct terminal *terminal, struct input_event *hold_quit)
{
int count = 0;
- int event_found = 0;
+ bool event_found = false;
struct x_display_info *dpyinfo = terminal->display_info.x;
block_input ();
if (x_filter_event (dpyinfo, &event))
continue;
#endif
- event_found = 1;
+ event_found = true;
count += handle_one_xevent (dpyinfo, &event, &finish, hold_quit);
/* Compute frame-relative coordinates for phys cursor. */
get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
- wd = w->phys_cursor_width;
+ wd = w->phys_cursor_width - 1;
/* The foreground of cursor_gc is typically the same as the normal
background color, which can cause the cursor box to be invisible. */
GCForeground, &xgcv);
gc = dpyinfo->scratch_cursor_gc;
+ /* When on R2L character, show cursor at the right edge of the
+ glyph, unless the cursor box is as wide as the glyph or wider
+ (the latter happens when x-stretch-cursor is non-nil). */
+ if ((cursor_glyph->resolved_level & 1) != 0
+ && cursor_glyph->pixel_width > wd)
+ {
+ x += cursor_glyph->pixel_width - wd;
+ if (wd > 0)
+ wd -= 1;
+ }
/* Set clipping, draw the rectangle, and reset clipping again. */
x_clip_to_row (w, row, TEXT_AREA, gc);
XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h - 1);
xgcv.background = xgcv.foreground = face->foreground;
else
xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
- xgcv.graphics_exposures = 0;
+ xgcv.graphics_exposures = False;
if (gc)
XChangeGC (dpy, gc, mask, &xgcv);
WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
width, row->height);
}
- else
+ else /* HBAR_CURSOR */
{
int dummy_x, dummy_y, dummy_h;
+ int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
if (width < 0)
width = row->height;
get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x,
&dummy_y, &dummy_h);
- XFillRectangle (dpy, window, gc,
- WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
+ if ((cursor_glyph->resolved_level & 1) != 0
+ && cursor_glyph->pixel_width > w->phys_cursor_width - 1)
+ x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
+ XFillRectangle (dpy, window, gc, x,
WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
row->height - width),
- w->phys_cursor_width, width);
+ w->phys_cursor_width - 1, width);
}
XSetClipMask (dpy, gc, None);
if (on_p)
{
w->phys_cursor_type = cursor_type;
- w->phys_cursor_on_p = 1;
+ w->phys_cursor_on_p = true;
if (glyph_row->exact_window_width_line_p
&& (glyph_row->reversed_p
? (w->phys_cursor.hpos < 0)
: (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])))
{
- glyph_row->cursor_in_fringe_p = 1;
+ glyph_row->cursor_in_fringe_p = true;
draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p);
}
else
/* Make the x-window of frame F use the gnu icon bitmap. */
-int
+bool
x_bitmap_icon (struct frame *f, Lisp_Object file)
{
ptrdiff_t bitmap_id;
if (FRAME_X_WINDOW (f) == 0)
- return 1;
+ return true;
/* Free up our existing icon bitmap and mask if any. */
if (f->output_data.x->icon_bitmap > 0)
/* Use gtk_window_set_icon_from_file () if available,
It's not restricted to bitmaps */
if (xg_set_icon (f, file))
- return 0;
+ return false;
#endif /* USE_GTK */
bitmap_id = x_create_bitmap_from_file (f, file);
x_create_bitmap_mask (f, bitmap_id);
#ifdef USE_GTK
- if (xg_set_icon (f, xg_default_icon_file)
- || xg_set_icon_from_xpm_data (f, gnu_xpm_bits))
- return 0;
+ if (xg_set_icon (f, xg_default_icon_file)
+ || xg_set_icon_from_xpm_data (f, gnu_xpm_bits))
+ {
+ FRAME_DISPLAY_INFO (f)->icon_bitmap_id = -2;
+ return false;
+ }
#elif defined (HAVE_XPM) && defined (HAVE_X_WINDOWS)
rc = x_create_bitmap_from_data (f, (char *) gnu_xbm_bits,
gnu_xbm_width, gnu_xbm_height);
if (rc == -1)
- return 1;
+ return true;
FRAME_DISPLAY_INFO (f)->icon_bitmap_id = rc;
x_create_bitmap_mask (f, FRAME_DISPLAY_INFO (f)->icon_bitmap_id);
x_wm_set_icon_pixmap (f, bitmap_id);
f->output_data.x->icon_bitmap = bitmap_id;
- return 0;
+ return false;
}
/* Make the x-window of frame F use a rectangle with text.
Use ICON_NAME as the text. */
-int
+bool
x_text_icon (struct frame *f, const char *icon_name)
{
if (FRAME_X_WINDOW (f) == 0)
- return 1;
+ return true;
{
XTextProperty text;
f->output_data.x->icon_bitmap = 0;
x_wm_set_icon_pixmap (f, 0);
- return 0;
+ return false;
}
\f
#define X_ERROR_MESSAGE_SIZE 200
x_error_message->string[0] = 0;
}
-#if 0 /* See comment in unwind_to_catch why calling this is a bad
+#if false
+ /* See comment in unwind_to_catch why calling this is a bad
* idea. --lorentey */
/* Close off all unclosed x_catch_errors calls. */
}
#endif
-#if 0
+#if false
static unsigned int x_wire_count;
x_trace_wire (void)
{
fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
}
-#endif /* ! 0 */
+#endif
\f
/************************************************************************
FRAME_COLUMN_WIDTH (f) = font->average_width;
FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (font);
- FRAME_TOOL_BAR_HEIGHT (f) = FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
+#ifndef USE_X_TOOLKIT
FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
-
- compute_fringe_widths (f, 1);
+#endif
/* Compute character columns occupied by scrollbar.
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)
- x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
- FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1);
+ adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
+ FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
+ false, Qfont);
}
#ifdef HAVE_X_I18N
#endif /* HAVE_X11R6 */
-#ifdef HAVE_X11R6
-/* This isn't prototyped in OSF 5.0 or 5.1a. */
-extern char *XSetIMValues (XIM, ...);
-#endif
-
/* Open the connection to the XIM server on display DPYINFO.
RESOURCE_NAME is the resource name Emacs uses. */
x_calc_absolute_position (f);
block_input ();
- x_wm_set_size_hint (f, (long) 0, 0);
+ x_wm_set_size_hint (f, 0, false);
modified_left = f->left_pos;
modified_top = f->top_pos;
modified_left, modified_top);
x_sync_with_move (f, f->left_pos, f->top_pos,
- FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
- ? 1 : 0);
+ FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
/* change_gravity is non-zero when this function is called from Lisp to
programmatically move a frame. In that case, we call
either the window manager type (A/B) is unknown or it is Type A but we
need to compute the top/left offset adjustment for this frame. */
- if (change_gravity != 0 &&
- (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
- || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
- && (FRAME_X_OUTPUT (f)->move_offset_left == 0
- && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
+ if (change_gravity != 0
+ && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
+ || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
+ && (FRAME_X_OUTPUT (f)->move_offset_left == 0
+ && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
x_check_expected_move (f, modified_left, modified_top);
unblock_input ();
}
-/* Return non-zero if _NET_SUPPORTING_WM_CHECK window exists and _NET_SUPPORTED
+/* Return true if _NET_SUPPORTING_WM_CHECK window exists and _NET_SUPPORTED
on the root window for frame F contains ATOMNAME.
This is how a WM check shall be done according to the Window Manager
Specification/Extended Window Manager Hints at
http://freedesktop.org/wiki/Specifications/wm-spec. */
-static int
+static bool
wm_supports (struct frame *f, Atom want_atom)
{
Atom actual_type;
unsigned long actual_size, bytes_remaining;
int i, rc, actual_format;
+ bool ret;
Window wmcheck_window;
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
Window target_window = dpyinfo->root_window;
- long max_len = 65536;
+ int max_len = 65536;
Display *dpy = FRAME_X_DISPLAY (f);
unsigned char *tmp_data = NULL;
Atom target_type = XA_WINDOW;
if (tmp_data) XFree (tmp_data);
x_uncatch_errors ();
unblock_input ();
- return 0;
+ return false;
}
wmcheck_window = *(Window *) tmp_data;
{
x_uncatch_errors ();
unblock_input ();
- return 0;
+ return false;
}
if (dpyinfo->net_supported_window != wmcheck_window)
if (tmp_data) XFree (tmp_data);
x_uncatch_errors ();
unblock_input ();
- return 0;
+ return false;
}
dpyinfo->net_supported_atoms = (Atom *)tmp_data;
dpyinfo->net_supported_window = wmcheck_window;
}
- rc = 0;
+ ret = false;
- for (i = 0; rc == 0 && i < dpyinfo->nr_net_supported_atoms; ++i)
- rc = dpyinfo->net_supported_atoms[i] == want_atom;
+ for (i = 0; !ret && i < dpyinfo->nr_net_supported_atoms; ++i)
+ ret = dpyinfo->net_supported_atoms[i] == want_atom;
x_uncatch_errors ();
unblock_input ();
- return rc;
+ return ret;
}
static void
-set_wm_state (Lisp_Object frame, int add, Atom atom, Atom value)
+set_wm_state (Lisp_Object frame, bool add, Atom atom, Atom value)
{
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (XFRAME (frame));
make_number (32),
/* 1 = add, 0 = remove */
Fcons
- (make_number (add ? 1 : 0),
+ (make_number (add),
Fcons
(make_fixnum_or_float (atom),
(value != 0
XSETFRAME (frame, f);
- set_wm_state (frame, NILP (new_value) ? 0 : 1,
+ set_wm_state (frame, !NILP (new_value),
dpyinfo->Xatom_net_wm_state_sticky, None);
}
/* Return the current _NET_WM_STATE.
SIZE_STATE is set to one of the FULLSCREEN_* values.
- STICKY is set to 1 if the sticky state is set, 0 if not.
+ Set *STICKY to the sticky state.
- Return non-zero if we are not hidden, zero if we are. */
+ Return true iff we are not hidden. */
-static int
+static bool
get_current_wm_state (struct frame *f,
Window window,
int *size_state,
- int *sticky)
+ bool *sticky)
{
Atom actual_type;
unsigned long actual_size, bytes_remaining;
- int i, rc, actual_format, is_hidden = 0;
+ int i, rc, actual_format;
+ bool is_hidden = false;
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
long max_len = 65536;
Display *dpy = FRAME_X_DISPLAY (f);
unsigned char *tmp_data = NULL;
Atom target_type = XA_ATOM;
- *sticky = 0;
+ *sticky = false;
*size_state = FULLSCREEN_NONE;
block_input ();
{
Atom a = ((Atom*)tmp_data)[i];
if (a == dpyinfo->Xatom_net_wm_state_hidden)
- {
- is_hidden = 1;
- f->output_data.x->net_wm_state_hidden_seen = 1;
- }
+ is_hidden = true;
else if (a == dpyinfo->Xatom_net_wm_state_maximized_horz)
{
if (*size_state == FULLSCREEN_HEIGHT)
else if (a == dpyinfo->Xatom_net_wm_state_fullscreen)
*size_state = FULLSCREEN_BOTH;
else if (a == dpyinfo->Xatom_net_wm_state_sticky)
- *sticky = 1;
+ *sticky = true;
}
if (tmp_data) XFree (tmp_data);
/* Do fullscreen as specified in extended window manager hints */
-static int
+static bool
do_ewmh_fullscreen (struct frame *f)
{
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
- int have_net_atom = wm_supports (f, dpyinfo->Xatom_net_wm_state);
- int cur, dummy;
+ bool have_net_atom = wm_supports (f, dpyinfo->Xatom_net_wm_state);
+ int cur;
+ bool dummy;
- (void)get_current_wm_state (f, FRAME_OUTER_WINDOW (f), &cur, &dummy);
+ get_current_wm_state (f, FRAME_OUTER_WINDOW (f), &cur, &dummy);
/* Some window managers don't say they support _NET_WM_STATE, but they do say
they support _NET_WM_STATE_FULLSCREEN. Try that also. */
switch (f->want_fullscreen)
{
case FULLSCREEN_BOTH:
- if (cur == FULLSCREEN_WIDTH || cur == FULLSCREEN_MAXIMIZED
- || cur == FULLSCREEN_HEIGHT)
- set_wm_state (frame, 0, dpyinfo->Xatom_net_wm_state_maximized_horz,
- dpyinfo->Xatom_net_wm_state_maximized_vert);
- set_wm_state (frame, 1, dpyinfo->Xatom_net_wm_state_fullscreen, None);
+ if (cur != FULLSCREEN_BOTH)
+ set_wm_state (frame, true, dpyinfo->Xatom_net_wm_state_fullscreen,
+ None);
break;
case FULLSCREEN_WIDTH:
if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_HEIGHT
|| cur == FULLSCREEN_MAXIMIZED)
- set_wm_state (frame, 0, dpyinfo->Xatom_net_wm_state_fullscreen,
+ set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
dpyinfo->Xatom_net_wm_state_maximized_vert);
if (cur != FULLSCREEN_MAXIMIZED)
- set_wm_state (frame, 1, dpyinfo->Xatom_net_wm_state_maximized_horz, None);
+ set_wm_state (frame, true,
+ dpyinfo->Xatom_net_wm_state_maximized_horz, None);
break;
case FULLSCREEN_HEIGHT:
if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_WIDTH
|| cur == FULLSCREEN_MAXIMIZED)
- set_wm_state (frame, 0, dpyinfo->Xatom_net_wm_state_fullscreen,
+ set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
dpyinfo->Xatom_net_wm_state_maximized_horz);
if (cur != FULLSCREEN_MAXIMIZED)
- set_wm_state (frame, 1, dpyinfo->Xatom_net_wm_state_maximized_vert, None);
+ set_wm_state (frame, true,
+ dpyinfo->Xatom_net_wm_state_maximized_vert, None);
break;
case FULLSCREEN_MAXIMIZED:
if (cur == FULLSCREEN_BOTH)
- set_wm_state (frame, 0, dpyinfo->Xatom_net_wm_state_fullscreen, None);
- set_wm_state (frame, 1, dpyinfo->Xatom_net_wm_state_maximized_horz,
+ set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
+ None);
+ set_wm_state (frame, true,
+ dpyinfo->Xatom_net_wm_state_maximized_horz,
dpyinfo->Xatom_net_wm_state_maximized_vert);
break;
case FULLSCREEN_NONE:
if (cur == FULLSCREEN_BOTH)
- set_wm_state (frame, 0, dpyinfo->Xatom_net_wm_state_fullscreen, None);
+ set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
+ None);
else
- set_wm_state (frame, 0, dpyinfo->Xatom_net_wm_state_maximized_horz,
+ set_wm_state (frame, false,
+ dpyinfo->Xatom_net_wm_state_maximized_horz,
dpyinfo->Xatom_net_wm_state_maximized_vert);
}
}
-static int
+static bool
x_handle_net_wm_state (struct frame *f, const XPropertyEvent *event)
{
int value = FULLSCREEN_NONE;
Lisp_Object lval;
- int sticky = 0;
- int not_hidden = get_current_wm_state (f, event->window, &value, &sticky);
+ bool sticky = false;
+ bool not_hidden = get_current_wm_state (f, event->window, &value, &sticky);
lval = Qnil;
switch (value)
XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
adjusted_left, adjusted_top);
- x_sync_with_move (f, expected_left, expected_top, 0);
+ x_sync_with_move (f, expected_left, expected_top, false);
}
else
/* It's a "Type B" window manager. We don't have to adjust the
of an exact comparison. */
static void
-x_sync_with_move (struct frame *f, int left, int top, int fuzzy)
+x_sync_with_move (struct frame *f, int left, int top, bool fuzzy)
{
int count = 0;
if (eabs (current_left - left) <= 10
&& eabs (current_top - top) <= 40)
return;
- }
+ }
else if (current_left == left && current_top == top)
return;
}
/* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
will then return up-to-date position info. */
- wait_reading_process_output (0, 500000, 0, 0, Qnil, NULL, 0);
+ wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0);
}
while (f->wait_event_type)
{
- pending_signals = 1;
+ pending_signals = true;
totally_unblock_input ();
/* XTread_socket is called after unblock. */
block_input ();
}
-/* Change the size of frame F's X window to COLS/ROWS in the case F
- doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
+/* Change the size of frame F's X window to WIDTH/HEIGHT in the case F
+ doesn't have a widget. If CHANGE_GRAVITY, change to
top-left-corner window gravity for this size change and subsequent
- size changes. Otherwise we leave the window gravity unchanged. */
+ size changes. Otherwise leave the window gravity unchanged. */
static void
-x_set_window_size_1 (struct frame *f, int change_gravity, int width, int height, bool pixelwise)
+x_set_window_size_1 (struct frame *f, bool change_gravity,
+ int width, int height, bool pixelwise)
{
int pixelwidth, pixelheight;
- check_frame_size (f, &width, &height, pixelwise);
-
- compute_fringe_widths (f, 0);
-
- pixelwidth = ((pixelwise
- ? FRAME_TEXT_TO_PIXEL_WIDTH (f, width)
- : FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width))
- + FRAME_TOOLBAR_WIDTH (f));
+ pixelwidth = (pixelwise
+ ? FRAME_TEXT_TO_PIXEL_WIDTH (f, width)
+ : FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width));
pixelheight = ((pixelwise
? FRAME_TEXT_TO_PIXEL_HEIGHT (f, height)
- : FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height))
- + FRAME_MENUBAR_HEIGHT (f)
- + FRAME_TOOLBAR_HEIGHT (f));
+ : FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height)));
+
if (change_gravity) f->win_gravity = NorthWestGravity;
- x_wm_set_size_hint (f, (long) 0, 0);
+ x_wm_set_size_hint (f, 0, false);
XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
- pixelwidth, pixelheight);
+ pixelwidth, pixelheight + FRAME_MENUBAR_HEIGHT (f));
/* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
wouldn't be reported in the frame parameters until some random
point in the future when the ConfigureNotify event arrives.
- We pass 1 for DELAY since we can't run Lisp code inside of
+ Pass true for DELAY since we can't run Lisp code inside of
a BLOCK_INPUT. */
/* But the ConfigureNotify may in fact never arrive, and then this is
x_wait_for_event (f, ConfigureNotify);
else
{
- change_frame_size (f, width, height, 0, 1, 0, 1);
+ change_frame_size (f, pixelwidth, pixelheight, false, true, false, true);
x_sync (f);
}
}
/* Call this to change the size of frame F's x-window.
- If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
+ If CHANGE_GRAVITY, change to top-left-corner window gravity
for this size change and subsequent size changes.
Otherwise we leave the window gravity unchanged. */
void
-x_set_window_size (struct frame *f, int change_gravity, int width, int height, bool pixelwise)
+x_set_window_size (struct frame *f, bool change_gravity,
+ int width, int height, bool pixelwise)
{
block_input ();
- check_frame_size (f, &width, &height, pixelwise);
-
+ /* The following breaks our calculations. If it's really needed,
+ think of something else. */
+#if false
if (NILP (tip_frame) || XFRAME (tip_frame) != f)
{
int text_width, text_height;
text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, FRAME_PIXEL_WIDTH (f));
text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelh);
- change_frame_size (f, text_width, text_height, 0, 1, 0, 1);
+ change_frame_size (f, text_width, text_height, false, true, false, true);
}
+#endif
#ifdef USE_GTK
if (FRAME_GTK_WIDGET (f))
#else /* not USE_GTK */
x_set_window_size_1 (f, change_gravity, width, height, pixelwise);
-#if !defined USE_X_TOOLKIT
x_clear_under_internal_border (f);
-#endif
#endif /* not USE_GTK */
cancel_mouse_face (f);
unblock_input ();
-}
-\f
-/* Mouse warping. */
-
-void
-x_set_mouse_position (struct frame *f, int x, int y)
-{
- int pix_x, pix_y;
-
- pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
- pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
-
- if (pix_x < 0) pix_x = 0;
- if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
-
- if (pix_y < 0) pix_y = 0;
- if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
-
- block_input ();
- XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
- 0, 0, 0, 0, pix_x, pix_y);
- unblock_input ();
+ do_pending_window_change (false);
}
/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
void
-x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
+frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
{
block_input ();
}
static void
-XTframe_raise_lower (struct frame *f, int raise_flag)
+XTframe_raise_lower (struct frame *f, bool raise_flag)
{
if (raise_flag)
x_raise_frame (f);
&& ! f->output_data.x->asked_for_visible)
x_set_offset (f, f->left_pos, f->top_pos, 0);
- f->output_data.x->asked_for_visible = 1;
+ f->output_data.x->asked_for_visible = true;
if (! EQ (Vx_no_window_manager, Qt))
x_wm_set_window_state (f, NormalState);
/* This must be before UNBLOCK_INPUT
since events that arrive in response to the actions above
will set it when they are handled. */
- int previously_visible = f->output_data.x->has_been_visible;
+ bool previously_visible = f->output_data.x->has_been_visible;
original_left = f->left_pos;
original_top = f->top_pos;
program-specified, so that when the window is mapped again, it will be
placed at the same location, without forcing the user to position it
by hand again (they have already done that once for this window.) */
- x_wm_set_size_hint (f, (long) 0, 1);
+ x_wm_set_size_hint (f, 0, true);
#ifdef USE_GTK
if (FRAME_GTK_OUTER_WIDGET (f))
FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
and synchronize with the server to make sure we agree. */
SET_FRAME_VISIBLE (f, 0);
- SET_FRAME_ICONIFIED (f, 0);
+ SET_FRAME_ICONIFIED (f, false);
x_sync (f);
gtk_window_iconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
SET_FRAME_VISIBLE (f, 0);
- SET_FRAME_ICONIFIED (f, 1);
+ SET_FRAME_ICONIFIED (f, true);
unblock_input ();
return;
}
that an invisible frame was changed to an icon,
so we have to record it here. */
SET_FRAME_VISIBLE (f, 0);
- SET_FRAME_ICONIFIED (f, 1);
+ SET_FRAME_ICONIFIED (f, true);
unblock_input ();
return;
}
if (!result)
error ("Can't notify window manager of iconification");
- SET_FRAME_ICONIFIED (f, 1);
+ SET_FRAME_ICONIFIED (f, true);
SET_FRAME_VISIBLE (f, 0);
block_input ();
XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
}
- SET_FRAME_ICONIFIED (f, 1);
+ SET_FRAME_ICONIFIED (f, true);
SET_FRAME_VISIBLE (f, 0);
XFlush (FRAME_X_DISPLAY (f));
commands to the X server. */
if (dpyinfo->display)
{
+ /* Always exit with visible pointer to avoid weird issue
+ with Xfixes (Bug#17609). */
+ if (f->pointer_invisible)
+ FRAME_DISPLAY_INFO (f)->toggle_visible_pointer (f, 0);
+
/* We must free faces before destroying windows because some
font-driver (e.g. xft) access a window while finishing a
face. */
XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
free_frame_menubar (f);
+
+ if (f->shell_position)
+ xfree (f->shell_position);
#else /* !USE_X_TOOLKIT */
#ifdef USE_GTK
unload_color (f, f->output_data.x->scroll_bar_background_pixel);
if (f->output_data.x->scroll_bar_foreground_pixel != -1)
unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
-#ifdef USE_TOOLKIT_SCROLL_BARS
+#if defined (USE_LUCID) && defined (USE_TOOLKIT_SCROLL_BARS)
/* Scrollbar shadow colors. */
if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
-#endif /* USE_TOOLKIT_SCROLL_BARS */
+#endif /* USE_LUCID && USE_TOOLKIT_SCROLL_BARS */
if (f->output_data.x->white_relief.pixel != -1)
unload_color (f, f->output_data.x->white_relief.pixel);
if (f->output_data.x->black_relief.pixel != -1)
XSizeHints size_hints;
Window window = FRAME_OUTER_WINDOW (f);
+ if (!window)
+ return;
+
#ifdef USE_X_TOOLKIT
if (f->output_data.x->widget)
{
base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
- check_frame_size (f, &min_cols, &min_rows, 0);
-
if (frame_resize_pixelwise)
/* Needed to prevent a bad protocol error crash when making the
frame size very small. */
/* Whether atimer for Xt timeouts is activated or not. */
-static int x_timeout_atimer_activated_flag;
+static bool x_timeout_atimer_activated_flag;
#endif /* USE_X_TOOLKIT */
/* Test whether two display-name strings agree up to the dot that separates
the screen number from the server number. */
-static int
+static bool
same_x_server (const char *name1, const char *name2)
{
- int seen_colon = 0;
- const char *system_name = SSDATA (Vsystem_name);
- ptrdiff_t system_name_length = SBYTES (Vsystem_name);
+ bool seen_colon = false;
+ Lisp_Object sysname = Fsystem_name ();
+ const char *system_name = SSDATA (sysname);
+ ptrdiff_t system_name_length = SBYTES (sysname);
ptrdiff_t length_until_period = 0;
while (system_name[length_until_period] != 0
for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
{
if (*name1 == ':')
- seen_colon = 1;
+ seen_colon = true;
if (seen_colon && *name1 == '.')
- return 1;
+ return true;
}
return (seen_colon
&& (*name1 == '.' || *name1 == '\0')
*bits = nr;
}
-/* Return 1 if display DISPLAY is available for use, 0 otherwise.
+/* Return true iff display DISPLAY is available for use.
But don't permanently open it, just test its availability. */
bool
x_display_ok (const char *display)
{
Display *dpy = XOpenDisplay (display);
- return dpy ? (XCloseDisplay (dpy), 1) : 0;
+ if (!dpy)
+ return false;
+ XCloseDisplay (dpy);
+ return true;
}
#ifdef USE_GTK
}
#endif
+/* Create invisible cursor on X display referred by DPYINFO. */
+
+static Cursor
+make_invisible_cursor (struct x_display_info *dpyinfo)
+{
+ Display *dpy = dpyinfo->display;
+ static char const no_data[] = { 0 };
+ Pixmap pix;
+ XColor col;
+ Cursor c = 0;
+
+ x_catch_errors (dpy);
+ pix = XCreateBitmapFromData (dpy, dpyinfo->root_window, no_data, 1, 1);
+ if (! x_had_errors_p (dpy) && pix != None)
+ {
+ Cursor pixc;
+ col.pixel = 0;
+ col.red = col.green = col.blue = 0;
+ col.flags = DoRed | DoGreen | DoBlue;
+ pixc = XCreatePixmapCursor (dpy, pix, pix, &col, &col, 0, 0);
+ if (! x_had_errors_p (dpy) && pixc != None)
+ c = pixc;
+ XFreePixmap (dpy, pix);
+ }
+
+ x_uncatch_errors ();
+
+ return c;
+}
+
+/* True if DPY supports Xfixes extension >= 4. */
+
+static bool
+x_probe_xfixes_extension (Display *dpy)
+{
+#ifdef HAVE_XFIXES
+ int major, minor;
+ return XFixesQueryVersion (dpy, &major, &minor) && major >= 4;
+#else
+ return false;
+#endif /* HAVE_XFIXES */
+}
+
+/* Toggle mouse pointer visibility on frame F by using Xfixes functions. */
+
+static void
+xfixes_toggle_visible_pointer (struct frame *f, bool invisible)
+{
+#ifdef HAVE_XFIXES
+ if (invisible)
+ XFixesHideCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+ else
+ XFixesShowCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+ f->pointer_invisible = invisible;
+#else
+ emacs_abort ();
+#endif /* HAVE_XFIXES */
+}
+
+/* Toggle mouse pointer visibility on frame F by using invisible cursor. */
+
+static void
+x_toggle_visible_pointer (struct frame *f, bool invisible)
+{
+ eassert (FRAME_DISPLAY_INFO (f)->invisible_cursor != 0);
+ if (invisible)
+ XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->invisible_cursor);
+ else
+ XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ f->output_data.x->current_cursor);
+ f->pointer_invisible = invisible;
+}
+
+/* Setup pointer blanking, prefer Xfixes if available. */
+
+static void
+x_setup_pointer_blanking (struct x_display_info *dpyinfo)
+{
+ /* FIXME: the brave tester should set EMACS_XFIXES because we're suspecting
+ X server bug, see http://debbugs.gnu.org/cgi/bugreport.cgi?bug=17609. */
+ if (egetenv ("EMACS_XFIXES") && x_probe_xfixes_extension (dpyinfo->display))
+ dpyinfo->toggle_visible_pointer = xfixes_toggle_visible_pointer;
+ else
+ {
+ dpyinfo->toggle_visible_pointer = x_toggle_visible_pointer;
+ dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo);
+ }
+}
+
/* Current X display connection identifier. Incremented for each next
connection established. */
static unsigned x_display_id;
struct x_display_info *
x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
{
- int connection;
Display *dpy;
struct terminal *terminal;
struct x_display_info *dpyinfo;
XSetLocaleModifiers ("");
- /* Emacs can only handle core input events, so make sure
- Gtk doesn't use Xinput or Xinput2 extensions. */
- xputenv ("GDK_CORE_DEVICE_EVENTS=1");
-
/* 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
argv[argc++] = "-xrm";
argv[argc++] = xrm_option;
}
- turn_on_atimers (0);
+ turn_on_atimers (false);
dpy = XtOpenDisplay (Xt_app_con, SSDATA (display_name),
resource_name, EMACS_CLASS,
emacs_options, XtNumber (emacs_options),
&argc, argv);
- turn_on_atimers (1);
+ turn_on_atimers (true);
#ifdef HAVE_X11XTR6
/* I think this is to compensate for XtSetLanguageProc. */
/* Set the name of the terminal. */
terminal->name = xlispstrdup (display_name);
-#if 0
+#if false
XSetAfterFunction (x_current_display, x_trace_wire);
-#endif /* ! 0 */
+#endif
lim = min (PTRDIFF_MAX, SIZE_MAX) - sizeof "@";
- if (lim - SBYTES (Vinvocation_name) < SBYTES (Vsystem_name))
+ Lisp_Object system_name = Fsystem_name ();
+ if (lim - SBYTES (Vinvocation_name) < SBYTES (system_name))
memory_full (SIZE_MAX);
dpyinfo->x_id = ++x_display_id;
dpyinfo->x_id_name = xmalloc (SBYTES (Vinvocation_name)
- + SBYTES (Vsystem_name) + 2);
- strcat (strcat (strcpy (dpyinfo->x_id_name, SSDATA (Vinvocation_name)), "@"),
- SSDATA (Vsystem_name));
+ + SBYTES (system_name) + 2);
+ char *nametail = lispstpcpy (dpyinfo->x_id_name, Vinvocation_name);
+ *nametail++ = '@';
+ lispstpcpy (nametail, system_name);
/* Figure out which modifier bits mean what. */
x_find_modifier_meanings (dpyinfo);
dpyinfo->vertical_scroll_bar_cursor
= XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
+ dpyinfo->horizontal_scroll_bar_cursor
+ = XCreateFontCursor (dpyinfo->display, XC_sb_h_double_arrow);
+
xrdb = x_load_resources (dpyinfo->display, xrm_option,
resource_name, EMACS_CLASS);
#ifdef HAVE_XRMSETDATABASE
{
if (dpyinfo->visual->class == PseudoColor)
{
- Lisp_Object value;
- value = display_x_get_resource (dpyinfo,
- build_string ("privateColormap"),
- build_string ("PrivateColormap"),
- Qnil, Qnil);
+ AUTO_STRING (privateColormap, "privateColormap");
+ AUTO_STRING (PrivateColormap, "PrivateColormap");
+ Lisp_Object value
+ = display_x_get_resource (dpyinfo, privateColormap,
+ PrivateColormap, Qnil, Qnil);
if (STRINGP (value)
&& (!strcmp (SSDATA (value), "true")
|| !strcmp (SSDATA (value), "on")))
#ifdef HAVE_XFT
{
- /* If we are using Xft, check dpi value in X resources.
- It is better we use it as well, since Xft will use it, as will all
- Gnome applications. If our real DPI is smaller or larger than the
- one Xft uses, our font will look smaller or larger than other
- for other applications, even if it is the same font name (monospace-10
- for example). */
- char *v = XGetDefault (dpyinfo->display, "Xft", "dpi");
+ /* If we are using Xft, the following precautions should be made:
+
+ 1. Make sure that the Xrender extension is added before the Xft one.
+ Otherwise, the close-display hook set by Xft is called after the one
+ for Xrender, and the former tries to re-add the latter. This results
+ in inconsistency of internal states and leads to X protocol error when
+ one reconnects to the same X server (Bug#1696).
+
+ 2. Check dpi value in X resources. It is better we use it as well,
+ since Xft will use it, as will all Gnome applications. If our real DPI
+ is smaller or larger than the one Xft uses, our font will look smaller
+ or larger than other for other applications, even if it is the same
+ font name (monospace-10 for example). */
+
+ int event_base, error_base;
+ char *v;
double d;
+
+ XRenderQueryExtension (dpyinfo->display, &event_base, &error_base);
+
+ v = XGetDefault (dpyinfo->display, "Xft", "dpi");
if (v != NULL && sscanf (v, "%lf", &d) == 1)
dpyinfo->resy = dpyinfo->resx = d;
}
ATOM_REFS_INIT ("DONE", Xatom_DONE)
ATOM_REFS_INIT ("PAGE", Xatom_PAGE)
ATOM_REFS_INIT ("SCROLLBAR", Xatom_Scrollbar)
+ ATOM_REFS_INIT ("HORIZONTAL_SCROLLBAR", Xatom_Horizontal_Scrollbar)
ATOM_REFS_INIT ("_XEMBED", Xatom_XEMBED)
/* EWMH */
ATOM_REFS_INIT ("_NET_WM_STATE", Xatom_net_wm_state)
};
int i;
- const int atom_count = sizeof (atom_refs) / sizeof (atom_refs[0]);
- /* 1 for _XSETTINGS_SN */
- const int total_atom_count = 1 + atom_count;
- Atom *atoms_return = xmalloc (total_atom_count * sizeof *atoms_return);
- char **atom_names = xmalloc (total_atom_count * sizeof *atom_names);
+ enum { atom_count = ARRAYELTS (atom_refs) };
+ /* 1 for _XSETTINGS_SN. */
+ enum { total_atom_count = 1 + atom_count };
+ Atom atoms_return[total_atom_count];
+ char *atom_names[total_atom_count];
static char const xsettings_fmt[] = "_XSETTINGS_S%d";
char xsettings_atom_name[sizeof xsettings_fmt - 2
+ INT_STRLEN_BOUND (int)];
for (i = 0; i < atom_count; i++)
atom_names[i] = (char *) atom_refs[i].name;
- /* Build _XSETTINGS_SN atom name */
+ /* Build _XSETTINGS_SN atom name. */
sprintf (xsettings_atom_name, xsettings_fmt,
XScreenNumberOfScreen (dpyinfo->screen));
atom_names[i] = xsettings_atom_name;
for (i = 0; i < atom_count; i++)
*(Atom *) ((char *) dpyinfo + atom_refs[i].offset) = atoms_return[i];
- /* Manual copy of last atom */
+ /* Manually copy last atom. */
dpyinfo->Xatom_xsettings_sel = atoms_return[i];
-
- xfree (atom_names);
- xfree (atoms_return);
}
dpyinfo->x_dnd_atoms_size = 8;
gray_bits, gray_width, gray_height,
1, 0, 1);
+ x_setup_pointer_blanking (dpyinfo);
+
#ifdef HAVE_X_I18N
xim_initialize (dpyinfo, resource_name);
#endif
xsettings_initialize (dpyinfo);
- connection = ConnectionNumber (dpyinfo->display);
-
/* This is only needed for distinguishing keyboard and process input. */
- if (connection != 0)
- add_keyboard_wait_descriptor (connection);
+ if (dpyinfo->connection != 0)
+ add_keyboard_wait_descriptor (dpyinfo->connection);
#ifdef F_SETOWN
- fcntl (connection, F_SETOWN, getpid ());
+ fcntl (dpyinfo->connection, F_SETOWN, getpid ());
#endif /* ! defined (F_SETOWN) */
if (interrupt_input)
- init_sigio (connection);
+ init_sigio (dpyinfo->connection);
#ifdef USE_LUCID
{
emacs_abort ();
if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
+ /* Do not free XFontStruct returned by the above call to XQueryFont.
+ This leads to X protocol errors at XtCloseDisplay (Bug#18403). */
x_uncatch_errors ();
}
#endif
/* See if we should run in synchronous mode. This is useful
for debugging X code. */
{
- Lisp_Object value;
- value = display_x_get_resource (dpyinfo,
- build_string ("synchronous"),
- build_string ("Synchronous"),
- Qnil, Qnil);
+ AUTO_STRING (synchronous, "synchronous");
+ AUTO_STRING (Synchronous, "Synchronous");
+ Lisp_Object value = display_x_get_resource (dpyinfo, synchronous,
+ Synchronous, Qnil, Qnil);
if (STRINGP (value)
&& (!strcmp (SSDATA (value), "true")
|| !strcmp (SSDATA (value), "on")))
}
{
- Lisp_Object value;
- value = display_x_get_resource (dpyinfo,
- build_string ("useXIM"),
- build_string ("UseXIM"),
- Qnil, Qnil);
+ AUTO_STRING (useXIM, "useXIM");
+ AUTO_STRING (UseXIM, "UseXIM");
+ Lisp_Object value = display_x_get_resource (dpyinfo, useXIM, UseXIM,
+ Qnil, Qnil);
#ifdef USE_XIM
if (STRINGP (value)
&& (!strcmp (SSDATA (value), "false")
#ifdef HAVE_X_SM
/* Only do this for the very first display in the Emacs session.
Ignore X session management when Emacs was first started on a
- tty. */
- if (terminal->id == 1)
+ tty or started as a daemon. */
+ if (terminal->id == 1 && ! IS_DAEMON)
x_session_initialize (dpyinfo);
#endif
x_process_timeouts (struct atimer *timer)
{
block_input ();
- x_timeout_atimer_activated_flag = 0;
+ x_timeout_atimer_activated_flag = false;
if (toolkit_scroll_bar_interaction || popup_activated ())
{
while (XtAppPending (Xt_app_con) & XtIMTimer)
{
struct timespec interval = make_timespec (0, 100 * 1000 * 1000);
start_atimer (ATIMER_RELATIVE, interval, x_process_timeouts, 0);
- x_timeout_atimer_activated_flag = 1;
+ x_timeout_atimer_activated_flag = true;
}
unblock_input ();
}
x_draw_window_cursor,
x_draw_vertical_window_border,
x_draw_window_divider,
- x_shift_glyphs_for_insert
+ x_shift_glyphs_for_insert,
+ x_show_hourglass,
+ x_hide_hourglass
};
xim_close_dpy (dpyinfo);
#endif
- /* If called from x_connection_closed, the display may already be closed
- and dpyinfo->display was set to 0 to indicate that. */
+ /* Normally, the display is available... */
if (dpyinfo->display)
{
x_destroy_all_bitmaps (dpyinfo);
don't destroy the database here in order to avoid the crash
in the above situations for now, though that may cause memory
leaks in other situations. */
-#if 0
+#if false
#ifdef HAVE_XRMSETDATABASE
XrmSetDatabase (dpyinfo->display, NULL);
#else
XCloseDisplay (dpyinfo->display);
#endif
#endif /* ! USE_GTK */
+ /* Do not close the connection here because it's already closed
+ by X(t)CloseDisplay (Bug#18403). */
+ dpyinfo->display = NULL;
}
- /* No more input on this descriptor. */
- if (0 <= dpyinfo->connection)
- delete_keyboard_wait_descriptor (dpyinfo->connection);
+ /* ...but if called from x_connection_closed, the display may already
+ be closed and dpyinfo->display was set to 0 to indicate that. Since
+ X server is most likely gone, explicit close is the only reliable
+ way to continue and avoid Bug#19147. */
+ else if (dpyinfo->connection >= 0)
+ emacs_close (dpyinfo->connection);
+ /* No more input on this descriptor. */
+ delete_keyboard_wait_descriptor (dpyinfo->connection);
/* Mark as dead. */
- dpyinfo->display = NULL;
dpyinfo->connection = -1;
+
x_delete_display (dpyinfo);
unblock_input ();
}
{
struct terminal *terminal;
- terminal = create_terminal ();
+ terminal = create_terminal (output_x_window, &x_redisplay_interface);
- terminal->type = output_x_window;
terminal->display_info.x = dpyinfo;
dpyinfo->terminal = terminal;
terminal->delete_glyphs_hook = x_delete_glyphs;
terminal->ring_bell_hook = XTring_bell;
terminal->toggle_invisible_pointer_hook = XTtoggle_invisible_pointer;
- terminal->reset_terminal_modes_hook = NULL;
- terminal->set_terminal_modes_hook = NULL;
terminal->update_begin_hook = x_update_begin;
terminal->update_end_hook = x_update_end;
- terminal->set_terminal_window_hook = NULL;
terminal->read_socket_hook = XTread_socket;
terminal->frame_up_to_date_hook = XTframe_up_to_date;
terminal->mouse_position_hook = XTmouse_position;
terminal->frame_rehighlight_hook = XTframe_rehighlight;
terminal->frame_raise_lower_hook = XTframe_raise_lower;
terminal->fullscreen_hook = XTfullscreen_hook;
+ terminal->menu_show_hook = x_menu_show;
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+ terminal->popup_dialog_hook = xw_popup_dialog;
+#endif
terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
+ terminal->set_horizontal_scroll_bar_hook = XTset_horizontal_scroll_bar;
terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
-
terminal->delete_frame_hook = x_destroy_window;
terminal->delete_terminal_hook = x_delete_terminal;
-
- terminal->rif = &x_redisplay_interface;
+ /* Other hooks are NULL by default. */
return terminal;
}
-void
+static void
x_initialize (void)
{
baud_rate = 19200;
x_noop_count = 0;
- last_tool_bar_item = -1;
- any_help_event_p = 0;
+ any_help_event_p = false;
ignore_next_mouse_click_timeout = 0;
#ifdef USE_GTK
XSetIOErrorHandler (x_io_error_quitter);
}
+#ifdef USE_GTK
+void
+init_xterm (void)
+{
+ /* Emacs can handle only core input events, so make sure
+ Gtk doesn't use Xinput or Xinput2 extensions. */
+ xputenv ("GDK_CORE_DEVICE_EVENTS=1");
+}
+#endif
void
syms_of_xterm (void)
to 4.1, set this to nil. You can also use `underline-minimum-offset'
to override the font's UNDERLINE_POSITION for small font display
sizes. */);
- x_use_underline_position_properties = 1;
+ x_use_underline_position_properties = true;
DEFVAR_BOOL ("x-underline-at-descent-line",
x_underline_at_descent_line,
A value of nil means to draw the underline according to the value of the
variable `x-use-underline-position-properties', which is usually at the
baseline level. The default value is nil. */);
- x_underline_at_descent_line = 0;
+ x_underline_at_descent_line = false;
DEFVAR_BOOL ("x-mouse-click-focus-ignore-position",
x_mouse_click_focus_ignore_position,
of nil, means that the selected window and cursor position changes to
reflect the mouse click position, while a non-nil value means that the
selected window or cursor position is preserved. */);
- x_mouse_click_focus_ignore_position = 0;
+ x_mouse_click_focus_ignore_position = false;
DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
doc: /* Which toolkit scroll bars Emacs uses, if any.