/* X Communication module for terminals which understand the X protocol.
Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "keymap.h"
#include "font.h"
#include "fontset.h"
+#include "xsettings.h"
+#include "xgselect.h"
#include "sysselect.h"
#ifdef USE_X_TOOLKIT
{
int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
- /* Internal border is drawn below the tool bar. */
- if (WINDOWP (f->tool_bar_window)
- && w == XWINDOW (f->tool_bar_window))
- y -= width;
-
BLOCK_INPUT;
x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
0, y, width, height, False);
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;
}
}
}
if (j < i)
{
font->driver->draw (s, j, i, x, y, 0);
+ if (s->face->overstrike)
+ font->driver->draw (s, j, i, x + 1, y, 0);
x += width;
}
xoff = LGLYPH_XOFF (glyph);
yoff = LGLYPH_YOFF (glyph);
wadjust = LGLYPH_WADJUST (glyph);
font->driver->draw (s, i, i + 1, x + xoff, y + yoff, 0);
+ if (s->face->overstrike)
+ font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff, 0);
x += wadjust;
j = i + 1;
width = 0;
}
}
if (j < i)
- font->driver->draw (s, j, i, x, y, 0);
+ {
+ font->driver->draw (s, j, i, x, y, 0);
+ if (s->face->overstrike)
+ font->driver->draw (s, j, i, x + 1, y, 0);
+ }
}
}
colors or something like that, then they should be notified. */
x_scroll_bar_clear (f);
+#if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
+ /* Make sure scroll bars are redrawn. As they aren't redrawn by
+ redisplay, do it here. */
+ gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
+#endif
+
XFlush (FRAME_X_DISPLAY (f));
UNBLOCK_INPUT;
BLOCK_INPUT;
{
+#ifdef USE_GTK
+ /* Use Gdk routines to draw. This way, we won't draw over scroll bars
+ when the scroll bars and the edit widget share the same X window. */
+ GdkGCValues vals;
+ GdkGC *gc;
+ vals.foreground.pixel = (FRAME_FOREGROUND_PIXEL (f)
+ ^ FRAME_BACKGROUND_PIXEL (f));
+ vals.function = GDK_XOR;
+ gc = gdk_gc_new_with_values (FRAME_GTK_WIDGET (f)->window,
+ &vals,
+ GDK_GC_FUNCTION
+ | GDK_GC_FOREGROUND);
+#define XFillRectangle(d, win, gc, x, y, w, h) \
+ gdk_draw_rectangle (FRAME_GTK_WIDGET (f)->window, \
+ gc, TRUE, x, y, w, h)
+#else
GC gc;
/* Create a GC that will use the GXxor function to flip foreground
gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
GCFunction | GCForeground, &values);
}
-
+#endif
{
/* Get the height not including a menu bar widget. */
int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
flash_left,
(FRAME_INTERNAL_BORDER_WIDTH (f)
- + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
+ + FRAME_TOP_MARGIN_HEIGHT (f)),
width, flash_height);
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
flash_left,
(height - flash_height
- FRAME_INTERNAL_BORDER_WIDTH (f)),
width, flash_height);
+
}
else
/* If it is short, flash it all. */
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
flash_left,
(FRAME_INTERNAL_BORDER_WIDTH (f)
- + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
+ + FRAME_TOP_MARGIN_HEIGHT (f)),
width, flash_height);
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
flash_left,
flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
+#ifdef USE_GTK
+ g_object_unref (G_OBJECT (gc));
+#undef XFillRectangle
+#else
XFreeGC (FRAME_X_DISPLAY (f), gc);
+#endif
x_flush (f);
}
}
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;
}
/* Scroll bar callback for GTK scroll bars. WIDGET is the scroll
bar widget. DATA is a pointer to the scroll_bar structure. */
-static void
-xg_scroll_callback (widget, data)
- GtkRange *widget;
- gpointer data;
+static gboolean
+xg_scroll_callback (GtkRange *range,
+ GtkScrollType scroll,
+ gdouble value,
+ gpointer user_data)
{
- struct scroll_bar *bar = (struct scroll_bar *) data;
- gdouble previous;
+ struct scroll_bar *bar = (struct scroll_bar *) user_data;
gdouble position;
- gdouble *p;
- int diff;
-
int part = -1, whole = 0, portion = 0;
- GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (widget));
+ GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
+ FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (range), XG_FRAME_DATA);
+ if (xg_ignore_gtk_scrollbar) return FALSE;
position = gtk_adjustment_get_value (adj);
- p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
- if (! p)
- {
- p = (gdouble*) xmalloc (sizeof (gdouble));
- *p = XG_SB_MIN;
- g_object_set_data (G_OBJECT (widget), XG_LAST_SB_DATA, p);
- }
-
- previous = *p;
- *p = position;
-
- if (xg_ignore_gtk_scrollbar) return;
- diff = (int) (position - previous);
-
- if (diff == (int) adj->step_increment)
- {
- part = scroll_bar_down_arrow;
- bar->dragging = Qnil;
- }
- else if (-diff == (int) adj->step_increment)
+ switch (scroll)
{
+ case GTK_SCROLL_JUMP:
+ /* Buttons 1 2 or 3 must be grabbed. */
+ if (FRAME_X_DISPLAY_INFO (f)->grabbed != 0
+ && FRAME_X_DISPLAY_INFO (f)->grabbed < (1 << 4))
+ {
+ part = scroll_bar_handle;
+ whole = adj->upper - adj->page_size;
+ portion = min ((int)position, whole);
+ bar->dragging = make_number ((int)portion);
+ }
+ break;
+ case GTK_SCROLL_STEP_BACKWARD:
part = scroll_bar_up_arrow;
bar->dragging = Qnil;
- }
- else if (diff == (int) adj->page_increment)
- {
- part = scroll_bar_below_handle;
+ break;
+ case GTK_SCROLL_STEP_FORWARD:
+ part = scroll_bar_down_arrow;
bar->dragging = Qnil;
- }
- else if (-diff == (int) adj->page_increment)
- {
+ break;
+ case GTK_SCROLL_PAGE_BACKWARD:
part = scroll_bar_above_handle;
bar->dragging = Qnil;
- }
- else
- {
- part = scroll_bar_handle;
- whole = adj->upper - adj->page_size;
- portion = min ((int)position, whole);
- bar->dragging = make_number ((int)portion);
+ break;
+ case GTK_SCROLL_PAGE_FORWARD:
+ part = scroll_bar_below_handle;
+ bar->dragging = Qnil;
+ break;
}
if (part >= 0)
last_scroll_bar_part = part;
x_send_scroll_bar_event (bar->window, part, portion, whole);
}
+
+ return FALSE;
}
+/* Callback for button release. Sets dragging to Qnil when dragging is done. */
+
+static gboolean
+xg_end_scroll_callback (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ struct scroll_bar *bar = (struct scroll_bar *) user_data;
+ bar->dragging = Qnil;
+ if (WINDOWP (window_being_scrolled))
+ {
+ x_send_scroll_bar_event (window_being_scrolled,
+ scroll_bar_end_scroll, 0, 0);
+ window_being_scrolled = Qnil;
+ }
+
+ return FALSE;
+}
+
+
#else /* not USE_GTK and not USE_MOTIF */
/* Xaw scroll bar callback. Invoked when the thumb is dragged.
BLOCK_INPUT;
xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
+ G_CALLBACK (xg_end_scroll_callback),
scroll_bar_name);
UNBLOCK_INPUT;
}
{
XEvent *xev = (XEvent *) gxev;
+ BLOCK_INPUT;
if (current_count >= 0)
{
struct x_display_info *dpyinfo;
/* Filter events for the current X input method.
GTK calls XFilterEvent but not for key press and release,
so we do it here. */
- if (xev->type == KeyPress || xev->type == KeyRelease)
- if (dpyinfo && x_filter_event (dpyinfo, xev))
- return GDK_FILTER_REMOVE;
+ if ((xev->type == KeyPress || xev->type == KeyRelease)
+ && dpyinfo
+ && x_filter_event (dpyinfo, xev))
+ {
+ UNBLOCK_INPUT;
+ return GDK_FILTER_REMOVE;
+ }
#endif
if (! dpyinfo)
current_finish = X_EVENT_NORMAL;
else
- {
- current_count +=
- handle_one_xevent (dpyinfo, xev, ¤t_finish,
- current_hold_quit);
- }
+ current_count +=
+ handle_one_xevent (dpyinfo, xev, ¤t_finish,
+ current_hold_quit);
}
else
current_finish = x_dispatch_event (xev, xev->xany.display);
+ UNBLOCK_INPUT;
+
if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP)
return GDK_FILTER_REMOVE;
goto done;
}
+ xft_settings_event (dpyinfo, &event);
+
f = x_any_window_to_frame (dpyinfo, event.xclient.window);
if (!f)
goto OTHER;
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;
x_handle_net_wm_state (f, &event.xproperty);
x_handle_property_notify (&event.xproperty);
+ xft_settings_event (dpyinfo, &event);
goto OTHER;
case ReparentNotify:
if (nchars == nbytes)
c = copy_bufptr[i], len = 1;
else
- c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
- nbytes - i, len);
+ c = STRING_CHAR_AND_LENGTH (copy_bufptr + i, len);
inev.ie.kind = (SINGLE_BYTE_CHAR_P (c)
? ASCII_KEYSTROKE_EVENT
: MULTIBYTE_CHAR_KEYSTROKE_EVENT);
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
}
goto OTHER;
+ case DestroyNotify:
+ xft_settings_event (dpyinfo, &event);
+ break;
+
default:
OTHER:
#ifdef USE_X_TOOLKIT
{
x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
x, y, width, height, False);
+#ifdef USE_GTK
+ /* Must queue a redraw, because scroll bars might have been cleared. */
+ if (FRAME_GTK_WIDGET (f))
+ gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
+#endif
}
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;
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)
- {
- /* When the frame is maximized/fullscreen or running under for
- example Xmonad, x_set_window_size will be a no-op.
- In that case, the right thing to do is extend rows/cols to
- the current frame size. We do that first if x_set_window_size
- turns out to not be a no-op (there is no way to know).
- The size will be adjusted again if the frame gets a
- ConfigureNotify event as a result of x_set_window_size. */
- int pixelh = FRAME_PIXEL_HEIGHT (f);
-#ifdef USE_X_TOOLKIT
- /* The menu bar is not part of text lines. The tool bar
- is however. */
- pixelh -= FRAME_MENUBAR_HEIGHT (f);
-#endif
- int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelh);
- int cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, FRAME_PIXEL_WIDTH (f));
-
- change_frame_size (f, rows, cols, 0, 1, 0);
- x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
- }
+ x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
}
#ifdef HAVE_X_I18N
"_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);
{
BLOCK_INPUT;
+ if (NILP (tip_frame) || XFRAME (tip_frame) != f)
+ {
+ int r, c;
+
+ /* When the frame is maximized/fullscreen or running under for
+ example Xmonad, x_set_window_size_1 will be a no-op.
+ In that case, the right thing to do is extend rows/cols to
+ the current frame size. We do that first if x_set_window_size_1
+ turns out to not be a no-op (there is no way to know).
+ The size will be adjusted again if the frame gets a
+ ConfigureNotify event as a result of x_set_window_size. */
+ int pixelh = FRAME_PIXEL_HEIGHT (f);
+#ifdef USE_X_TOOLKIT
+ /* The menu bar is not part of text lines. The tool bar
+ is however. */
+ pixelh -= FRAME_MENUBAR_HEIGHT (f);
+#endif
+ r = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelh);
+ /* Update f->scroll_bar_actual_width because it is used in
+ FRAME_PIXEL_WIDTH_TO_TEXT_COLS. */
+ f->scroll_bar_actual_width
+ = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
+ c = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, FRAME_PIXEL_WIDTH (f));
+ change_frame_size (f, r, c, 0, 1, 0);
+ }
+
#ifdef USE_GTK
if (FRAME_GTK_WIDGET (f))
xg_frame_set_char_size (f, cols, rows);
{
Pixmap icon_pixmap, icon_mask;
-#ifndef USE_X_TOOLKIT
+#if !defined USE_X_TOOLKIT && !defined USE_GTK
Window window = FRAME_OUTER_WINDOW (f);
#endif
return dpy_ok;
}
+#ifdef USE_GTK
+static void
+my_log_handler (log_domain, log_level, message, user_data)
+ const gchar *log_domain;
+ GLogLevelFlags log_level;
+ const gchar *message;
+ gpointer user_data;
+{
+ if (!strstr (message, "g_set_prgname"))
+ fprintf (stderr, "%s-WARNING **: %s\n", log_domain, message);
+}
+#endif
+
/* Open a connection to X display DISPLAY_NAME, and return
the structure that describes the open display.
If we cannot contact the display, return null. */
int argc;
char *argv[NUM_ARGV];
char **argv2 = argv;
- GdkAtom atom;
-
+ guint id;
#ifndef HAVE_GTK_MULTIDISPLAY
if (!EQ (Vinitial_window_system, Qx))
error ("Sorry, you cannot connect to X servers with the GTK toolkit");
XSetLocaleModifiers ("");
+ /* Work around GLib bug that outputs a faulty warning. See
+ https://bugzilla.gnome.org/show_bug.cgi?id=563627. */
+ id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
+ | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
gtk_init (&argc, &argv2);
+ g_log_remove_handler ("GLib", id);
/* gtk_init does set_locale. We must fix locale after calling it. */
fixup_locale ();
terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
init_kboard (terminal->kboard);
terminal->kboard->Vwindow_system = Qx;
+
+ /* Add the keyboard to the list before running Lisp code (via
+ Qvendor_specific_keysyms below), since these are not traced
+ via terminals but only through all_kboards. */
+ terminal->kboard->next_kboard = all_kboards;
+ all_kboards = terminal->kboard;
+
if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
{
char *vendor = ServerVendor (dpy);
- /* Temporarily hide the partially initialized terminal */
+
+ /* Protect terminal from GC before removing it from the
+ list of terminals. */
+ struct gcpro gcpro1;
+ Lisp_Object gcpro_term;
+ XSETTERMINAL (gcpro_term, terminal);
+ GCPRO1 (gcpro_term);
+
+ /* Temporarily hide the partially initialized terminal. */
terminal_list = terminal->next_terminal;
UNBLOCK_INPUT;
terminal->kboard->Vsystem_key_alist
BLOCK_INPUT;
terminal->next_terminal = terminal_list;
terminal_list = terminal;
+ UNGCPRO;
}
- terminal->kboard->next_kboard = all_kboards;
- all_kboards = terminal->kboard;
/* Don't let the initial kboard remain current longer than necessary.
That would cause problems if a file loaded on startup tries to
prompt in the mini-buffer. */
dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
dpyinfo->visual, AllocNone);
+#ifdef HAVE_XFT
{
- int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
- double pixels = DisplayHeight (dpyinfo->display, screen_number);
- double mm = DisplayHeightMM (dpyinfo->display, screen_number);
- /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
- dpyinfo->resy = (mm < 1) ? 100 : pixels * 25.4 / mm;
- pixels = DisplayWidth (dpyinfo->display, screen_number);
- mm = DisplayWidthMM (dpyinfo->display, screen_number);
- /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
- dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm;
+ /* 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");
+ double d;
+ if (v != NULL && sscanf (v, "%lf", &d) == 1)
+ dpyinfo->resy = dpyinfo->resx = d;
}
+#endif
+
+ if (dpyinfo->resy < 1)
+ {
+ int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
+ double pixels = DisplayHeight (dpyinfo->display, screen_number);
+ double mm = DisplayHeightMM (dpyinfo->display, screen_number);
+ /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
+ dpyinfo->resy = (mm < 1) ? 100 : pixels * 25.4 / mm;
+ pixels = DisplayWidth (dpyinfo->display, screen_number);
+ mm = DisplayWidthMM (dpyinfo->display, screen_number);
+ /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
+ dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm;
+ }
dpyinfo->Xatom_wm_protocols
= XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
= XInternAtom (dpyinfo->display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
dpyinfo->Xatom_net_wm_state_sticky
= XInternAtom (dpyinfo->display, "_NET_WM_STATE_STICKY", False);
-
+ dpyinfo->Xatom_net_window_type
+ = XInternAtom (dpyinfo->display, "_NET_WM_WINDOW_TYPE", False);
+ dpyinfo->Xatom_net_window_type_tooltip
+ = XInternAtom (dpyinfo->display, "_NET_WM_WINDOW_TYPE_TOOLTIP", False);
+ dpyinfo->Xatom_net_frame_extents
+ = XInternAtom (dpyinfo->display, "_NET_FRAME_EXTENTS", False);
dpyinfo->cut_buffers_initialized = 0;
dpyinfo->x_dnd_atoms_size = 8;
xim_initialize (dpyinfo, resource_name);
#endif
+ xsettings_initialize (dpyinfo);
+
#ifdef subprocesses
/* This is only needed for distinguishing keyboard and process input. */
if (connection != 0)
x_delete_display (dpyinfo)
struct x_display_info *dpyinfo;
{
- int i;
struct terminal *t;
/* Close all frames and delete the generic struct terminal for this
x_delete_terminal (struct terminal *terminal)
{
struct x_display_info *dpyinfo = terminal->display_info.x;
- int i;
/* Protect against recursive calls. delete_frame in
delete_terminal calls us back when it deletes our last frame. */
#endif /* ! USE_GTK */
}
+ /* Mark as dead. */
+ dpyinfo->display = NULL;
x_delete_display (dpyinfo);
UNBLOCK_INPUT;
}
XSetIOErrorHandler (x_io_error_quitter);
signal (SIGPIPE, x_connection_signal);
+
+ xgselect_initialize ();
}