/* X Communication module for terminals which understand the X protocol.
Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of GNU Emacs.
Window window = FRAME_X_WINDOW (f);
GC gc = f->output_data.x->normal_gc;
struct face *face = p->face;
- int rowY;
/* Must clip because of partially visible lines. */
- rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
- if (p->y < rowY)
- {
- /* Adjust position of "bottom aligned" bitmap on partially
- visible last row. */
- int oldY = row->y;
- int oldVH = row->visible_height;
- row->visible_height = p->h;
- row->y -= rowY - p->y;
- x_clip_to_row (w, row, -1, gc);
- row->y = oldY;
- row->visible_height = oldVH;
- }
- else
- x_clip_to_row (w, row, -1, gc);
+ x_clip_to_row (w, row, -1, gc);
if (!p->overlay_p)
{
if (sb_width > 0)
{
- int left = WINDOW_SCROLL_BAR_AREA_X (w);
- int width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
- * FRAME_COLUMN_WIDTH (f));
+ int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
+ int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
+ * FRAME_COLUMN_WIDTH (f));
if (bx < 0)
{
/* Bitmap fills the fringe. */
- if (left + width == p->x)
- bx = left + sb_width;
- else if (p->x + p->wd == left)
- bx = left;
+ if (bar_area_x + bar_area_width == p->x)
+ bx = bar_area_x + sb_width;
+ else if (p->x + p->wd == bar_area_x)
+ bx = bar_area_x;
if (bx >= 0)
{
int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
- nx = width - sb_width;
+ nx = bar_area_width - sb_width;
by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
row->y));
ny = row->visible_height;
}
else
{
- if (left + width == bx)
+ if (bar_area_x + bar_area_width == bx)
{
- bx = left + sb_width;
- nx += width - sb_width;
+ bx = bar_area_x + sb_width;
+ nx += bar_area_width - sb_width;
}
- else if (bx + nx == left)
- nx += width - sb_width;
+ else if (bx + nx == bar_area_x)
+ nx += bar_area_width - sb_width;
}
}
}
fringe of W. */
window_box (w, -1, &x, &y, &width, &height);
+#ifdef USE_TOOLKIT_SCROLL_BARS
+ /* If the fringe is adjacent to the left (right) scroll bar of a
+ leftmost (rightmost, respectively) window, then extend its
+ background to the gap between the fringe and the bar. */
+ if ((WINDOW_LEFTMOST_P (w)
+ && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
+ || (WINDOW_RIGHTMOST_P (w)
+ && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
+ {
+ int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
+
+ if (sb_width > 0)
+ {
+ int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
+ int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
+ * FRAME_COLUMN_WIDTH (f));
+
+ if (bar_area_x + bar_area_width == x)
+ {
+ x = bar_area_x + sb_width;
+ width += bar_area_width - sb_width;
+ }
+ else if (x + width == bar_area_x)
+ width += bar_area_width - sb_width;
+ }
+ }
+#endif
+
from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
bottom_y = y + height;
return XSCROLL_BAR (bar);
}
- return 0;
+ return NULL;
}
goto OTHER;
#endif /* USE_X_TOOLKIT */
{
- XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
+ XSelectionClearEvent *eventp = &(event.xselectionclear);
inev.ie.kind = SELECTION_CLEAR_EVENT;
SELECTION_EVENT_DISPLAY (&inev.sie) = eventp->display;
goto OTHER;
#endif /* USE_X_TOOLKIT */
{
- XSelectionRequestEvent *eventp
- = (XSelectionRequestEvent *) &event;
+ XSelectionRequestEvent *eventp = &(event.xselectionrequest);
inev.ie.kind = SELECTION_REQUEST_EVENT;
SELECTION_EVENT_DISPLAY (&inev.sie) = eventp->display;
f->mouse_moved = 0;
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
- f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
+ f = x_menubar_window_to_frame (dpyinfo, &event);
/* For a down-event in the menu bar,
don't pass it to Xt right now.
Instead, save it away
delete_frame (frame, Qnoelisp);
}
- /* We have to close the display to inform Xt that it doesn't
- exist anymore. If we don't, Xt will continue to wait for
- events from the display. As a consequence, a sequence of
-
- M-x make-frame-on-display RET :1 RET
- ...kill the new frame, so that we get an IO error...
- M-x make-frame-on-display RET :1 RET
-
- will indefinitely wait in Xt for events for display `:1', opened
- in the first call to make-frame-on-display.
-
- Closing the display is reported to lead to a bus error on
- OpenWindows in certain situations. I suspect that is a bug
- in OpenWindows. I don't know how to circumvent it here. */
-
+ /* If DPYINFO is null, this means we didn't open the display in the
+ first place, so don't try to close it. */
if (dpyinfo)
{
#ifdef USE_X_TOOLKIT
- /* If DPYINFO is null, this means we didn't open the display
- in the first place, so don't try to close it. */
- {
- extern void (*fatal_error_signal_hook) P_ ((void));
- fatal_error_signal_hook = x_fatal_error_signal;
- XtCloseDisplay (dpy);
- fatal_error_signal_hook = NULL;
- }
-#endif
+ /* We have to close the display to inform Xt that it doesn't
+ exist anymore. If we don't, Xt will continue to wait for
+ events from the display. As a consequence, a sequence of
+
+ M-x make-frame-on-display RET :1 RET
+ ...kill the new frame, so that we get an IO error...
+ M-x make-frame-on-display RET :1 RET
+
+ will indefinitely wait in Xt for events for display `:1',
+ opened in the first call to make-frame-on-display.
+
+ Closing the display is reported to lead to a bus error on
+ OpenWindows in certain situations. I suspect that is a bug
+ in OpenWindows. I don't know how to circumvent it here. */
+ extern void (*fatal_error_signal_hook) P_ ((void));
+ fatal_error_signal_hook = x_fatal_error_signal;
+ XtCloseDisplay (dpy);
+ fatal_error_signal_hook = NULL;
+#endif /* USE_X_TOOLKIT */
#ifdef USE_GTK
- /* Due to bugs in some Gtk+ versions, just exit here if this
- is the last display/terminal. */
- if (terminal_list->next_terminal == NULL)
- {
- fprintf (stderr, "%s\n", error_msg);
- shut_down_emacs (0, 0, Qnil);
- exit (70);
- }
- xg_display_close (dpyinfo->display);
-#endif
+ /* A long-standing GTK bug prevents proper disconnect handling
+ (https://bugzilla.gnome.org/show_bug.cgi?id=85715). Once,
+ the resulting Glib error message loop filled a user's disk.
+ To avoid this, kill Emacs unconditionally on disconnect. */
+ shut_down_emacs (0, 0, Qnil);
+ fprintf (stderr, "%s\n\
+When compiled with GTK, Emacs cannot recover from X disconnects.\n\
+This is a GTK bug: https://bugzilla.gnome.org/show_bug.cgi?id=85715\n\
+For details, see etc/PROBLEMS.\n",
+ error_msg);
+ abort ();
+#endif /* USE_GTK */
/* Indicate that this display is dead. */
dpyinfo->display = 0;
"_NET_WM_STATE_STICKY", NULL);
}
+/* 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. */
+
+static void
+get_current_vm_state (struct frame *f,
+ Window window,
+ int *size_state,
+ int *sticky)
+{
+ Atom actual_type;
+ unsigned long actual_size, bytes_remaining;
+ int i, rc, actual_format;
+ struct x_display_info *dpyinfo = FRAME_X_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;
+ *size_state = FULLSCREEN_NONE;
+
+ BLOCK_INPUT;
+ x_catch_errors (dpy);
+ rc = XGetWindowProperty (dpy, window, dpyinfo->Xatom_net_wm_state,
+ 0, max_len, False, target_type,
+ &actual_type, &actual_format, &actual_size,
+ &bytes_remaining, &tmp_data);
+
+ if (rc != Success || actual_type != target_type || x_had_errors_p (dpy))
+ {
+ if (tmp_data) XFree (tmp_data);
+ x_uncatch_errors ();
+ UNBLOCK_INPUT;
+ return;
+ }
+
+ x_uncatch_errors ();
+
+ for (i = 0; i < actual_size; ++i)
+ {
+ Atom a = ((Atom*)tmp_data)[i];
+ if (a == dpyinfo->Xatom_net_wm_state_maximized_horz)
+ {
+ if (*size_state == FULLSCREEN_HEIGHT)
+ *size_state = FULLSCREEN_MAXIMIZED;
+ else
+ *size_state = FULLSCREEN_WIDTH;
+ }
+ else if (a == dpyinfo->Xatom_net_wm_state_maximized_vert)
+ {
+ if (*size_state == FULLSCREEN_WIDTH)
+ *size_state = FULLSCREEN_MAXIMIZED;
+ else
+ *size_state = FULLSCREEN_HEIGHT;
+ }
+ else if (a == dpyinfo->Xatom_net_wm_state_fullscreen_atom)
+ *size_state = FULLSCREEN_BOTH;
+ else if (a == dpyinfo->Xatom_net_wm_state_sticky)
+ *sticky = 1;
+ }
+
+ if (tmp_data) XFree (tmp_data);
+ UNBLOCK_INPUT;
+}
+
/* Do fullscreen as specified in extended window manager hints */
static int
struct frame *f;
{
int have_net_atom = wm_supports (f, "_NET_WM_STATE");
+ Lisp_Object lval = get_frame_param (f, Qfullscreen);
+ int cur, dummy;
+
+ get_current_vm_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. */
if (!have_net_atom)
have_net_atom = wm_supports (f, "_NET_WM_STATE_FULLSCREEN");
- if (have_net_atom)
+ if (have_net_atom && cur != f->want_fullscreen)
{
Lisp_Object frame;
const char *fs = "_NET_WM_STATE_FULLSCREEN";
XSETFRAME (frame, f);
- set_wm_state (frame, 0, fs, NULL);
- set_wm_state (frame, 0, fh, NULL);
- set_wm_state (frame, 0, fw, NULL);
-
- /* If there are _NET_ atoms we assume we have extended window manager
- hints. */
+ /* Keep number of calls to set_wm_state as low as possible.
+ Some window managers, or possible Gtk+, hangs when too many
+ are sent at once. */
switch (f->want_fullscreen)
{
case FULLSCREEN_BOTH:
+ if (cur == FULLSCREEN_WIDTH || cur == FULLSCREEN_MAXIMIZED
+ || cur == FULLSCREEN_HEIGHT)
+ set_wm_state (frame, 0, fw, fh);
set_wm_state (frame, 1, fs, NULL);
break;
case FULLSCREEN_WIDTH:
- set_wm_state (frame, 1, fw, NULL);
+ if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_HEIGHT
+ || cur == FULLSCREEN_MAXIMIZED)
+ set_wm_state (frame, 0, fs, fh);
+ if (cur != FULLSCREEN_MAXIMIZED)
+ set_wm_state (frame, 1, fw, NULL);
break;
case FULLSCREEN_HEIGHT:
- set_wm_state (frame, 1, fh, NULL);
+ if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_WIDTH
+ || cur == FULLSCREEN_MAXIMIZED)
+ set_wm_state (frame, 0, fs, fw);
+ if (cur != FULLSCREEN_MAXIMIZED)
+ set_wm_state (frame, 1, fh, NULL);
break;
case FULLSCREEN_MAXIMIZED:
+ if (cur == FULLSCREEN_BOTH)
+ set_wm_state (frame, 0, fs, NULL);
set_wm_state (frame, 1, fw, fh);
break;
+ case FULLSCREEN_NONE:
+ if (cur == FULLSCREEN_BOTH)
+ set_wm_state (frame, 0, fs, NULL);
+ else
+ set_wm_state (frame, 0, fw, fh);
}
f->want_fullscreen = FULLSCREEN_NONE;
struct frame *f;
XPropertyEvent *event;
{
- Atom actual_type;
- unsigned long actual_size, bytes_remaining;
- int i, rc, actual_format, value = FULLSCREEN_NONE;
- struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
- long max_len = 65536;
- Display *dpy = FRAME_X_DISPLAY (f);
- unsigned char *tmp_data = NULL;
- Atom target_type = XA_ATOM;
+ int value = FULLSCREEN_NONE;
Lisp_Object lval;
int sticky = 0;
- BLOCK_INPUT;
- x_catch_errors (dpy);
- rc = XGetWindowProperty (dpy, event->window,
- event->atom, 0, max_len, False, target_type,
- &actual_type, &actual_format, &actual_size,
- &bytes_remaining, &tmp_data);
-
- if (rc != Success || actual_type != target_type || x_had_errors_p (dpy))
- {
- if (tmp_data) XFree (tmp_data);
- x_uncatch_errors ();
- UNBLOCK_INPUT;
- return;
- }
-
- x_uncatch_errors ();
-
- for (i = 0; i < actual_size; ++i)
- {
- Atom a = ((Atom*)tmp_data)[i];
- if (a == dpyinfo->Xatom_net_wm_state_maximized_horz)
- {
- if (value == FULLSCREEN_HEIGHT)
- value = FULLSCREEN_MAXIMIZED;
- else
- value = FULLSCREEN_WIDTH;
- }
- else if (a == dpyinfo->Xatom_net_wm_state_maximized_vert)
- {
- if (value == FULLSCREEN_WIDTH)
- value = FULLSCREEN_MAXIMIZED;
- else
- value = FULLSCREEN_HEIGHT;
- }
- else if (a == dpyinfo->Xatom_net_wm_state_fullscreen_atom)
- value = FULLSCREEN_BOTH;
- else if (a == dpyinfo->Xatom_net_wm_state_sticky)
- sticky = 1;
- }
-
+ get_current_vm_state (f, event->window, &value, &sticky);
lval = Qnil;
switch (value)
{
store_frame_param (f, Qfullscreen, lval);
store_frame_param (f, Qsticky, sticky ? Qt : Qnil);
-
- if (tmp_data) XFree (tmp_data);
- UNBLOCK_INPUT;
}
/* Check if we need to resize the frame due to a fullscreen request.
if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
return; /* Only fullscreen without WM or with EWM hints (above). */
+ /* Setting fullscreen to nil doesn't do anything. We could save the
+ last non-fullscreen size and restore it, but it seems like a
+ lot of work for this unusual case (no window manager running). */
+
if (f->want_fullscreen != FULLSCREEN_NONE)
{
- int width = FRAME_COLS (f), height = FRAME_LINES (f);
+ int width = FRAME_PIXEL_WIDTH (f), height = FRAME_PIXEL_HEIGHT (f);
struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
switch (f->want_fullscreen)
case FULLSCREEN_HEIGHT:
height = x_display_pixel_height (dpyinfo);
}
-
- if (FRAME_COLS (f) != width || FRAME_LINES (f) != height)
- {
- change_frame_size (f, height, width, 0, 1, 0);
- SET_FRAME_GARBAGED (f);
- cancel_mouse_face (f);
- }
+
+ XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ width, height);
}
}
compute_fringe_widths (f, 0);
- pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols)
- + 2*f->border_width;
+ pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows)
- + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f)
- + 2*f->border_width;
+ + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
if (change_gravity) f->win_gravity = NorthWestGravity;
x_wm_set_size_hint (f, (long) 0, 0);
= XInternAtom (dpyinfo->display, "_NET_WM_WINDOW_TYPE", False);
dpyinfo->Xatom_net_window_type_tooltip
= XInternAtom (dpyinfo->display, "_NET_WM_WINDOW_TYPE_TOOLTIP", False);
-
+ dpyinfo->Xatom_net_frame_extents
+ = XInternAtom (dpyinfo->display, "_NET_FRAME_EXTENTS", False);
dpyinfo->cut_buffers_initialized = 0;
dpyinfo->x_dnd_atoms_size = 8;