+ /* Record in these vectors all the parms specified. */
+ Lisp_Object *parms;
+ Lisp_Object *values;
+ int i, p;
+ int left_no_change = 0, top_no_change = 0;
+ int icon_left_no_change = 0, icon_top_no_change = 0;
+ int fullscreen_is_being_set = 0;
+
+ struct gcpro gcpro1, gcpro2;
+
+ i = 0;
+ for (tail = alist; CONSP (tail); tail = Fcdr (tail))
+ i++;
+
+ parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
+ values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
+
+ /* Extract parm names and values into those vectors. */
+
+ i = 0;
+ for (tail = alist; CONSP (tail); tail = Fcdr (tail))
+ {
+ Lisp_Object elt;
+
+ elt = Fcar (tail);
+ parms[i] = Fcar (elt);
+ values[i] = Fcdr (elt);
+ i++;
+ }
+ /* TAIL and ALIST are not used again below here. */
+ alist = tail = Qnil;
+
+ GCPRO2 (*parms, *values);
+ gcpro1.nvars = i;
+ gcpro2.nvars = i;
+
+ /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
+ because their values appear in VALUES and strings are not valid. */
+ top = left = Qunbound;
+ icon_left = icon_top = Qunbound;
+
+ /* Provide default values for HEIGHT and WIDTH. */
+ width = (f->new_text_cols ? f->new_text_cols : FRAME_COLS (f));
+ height = (f->new_text_lines ? f->new_text_lines : FRAME_LINES (f));
+
+ /* Process foreground_color and background_color before anything else.
+ They are independent of other properties, but other properties (e.g.,
+ cursor_color) are dependent upon them. */
+ /* Process default font as well, since fringe widths depends on it. */
+ /* Also, process fullscreen, width and height depend upon that */
+ for (p = 0; p < i; p++)
+ {
+ Lisp_Object prop, val;
+
+ prop = parms[p];
+ val = values[p];
+ if (EQ (prop, Qforeground_color)
+ || EQ (prop, Qbackground_color)
+ || EQ (prop, Qfont)
+ || EQ (prop, Qfullscreen))
+ {
+ register Lisp_Object param_index, old_value;
+
+ old_value = get_frame_param (f, prop);
+ fullscreen_is_being_set |= EQ (prop, Qfullscreen);
+
+ if (NILP (Fequal (val, old_value)))
+ {
+ store_frame_param (f, prop, val);
+
+ param_index = Fget (prop, Qx_frame_parameter);
+ if (NATNUMP (param_index)
+ && (XFASTINT (param_index)
+ < sizeof (frame_parms)/sizeof (frame_parms[0]))
+ && rif->frame_parm_handlers[XINT (param_index)])
+ (*(rif->frame_parm_handlers[XINT (param_index)])) (f, val, old_value);
+ }
+ }
+ }
+
+ /* Now process them in reverse of specified order. */
+ for (i--; i >= 0; i--)
+ {
+ Lisp_Object prop, val;
+
+ prop = parms[i];
+ val = values[i];
+
+ if (EQ (prop, Qwidth) && NUMBERP (val))
+ width = XFASTINT (val);
+ else if (EQ (prop, Qheight) && NUMBERP (val))
+ height = XFASTINT (val);
+ else if (EQ (prop, Qtop))
+ top = val;
+ else if (EQ (prop, Qleft))
+ left = val;
+ else if (EQ (prop, Qicon_top))
+ icon_top = val;
+ else if (EQ (prop, Qicon_left))
+ icon_left = val;
+ else if (EQ (prop, Qforeground_color)
+ || EQ (prop, Qbackground_color)
+ || EQ (prop, Qfont)
+ || EQ (prop, Qfullscreen))
+ /* Processed above. */
+ continue;
+ else
+ {
+ register Lisp_Object param_index, old_value;
+
+ old_value = get_frame_param (f, prop);
+
+ store_frame_param (f, prop, val);
+
+ param_index = Fget (prop, Qx_frame_parameter);
+ if (NATNUMP (param_index)
+ && (XFASTINT (param_index)
+ < sizeof (frame_parms)/sizeof (frame_parms[0]))
+ && rif->frame_parm_handlers[XINT (param_index)])
+ (*(rif->frame_parm_handlers[XINT (param_index)])) (f, val, old_value);
+ }
+ }
+
+ /* Don't die if just one of these was set. */
+ if (EQ (left, Qunbound))
+ {
+ left_no_change = 1;
+ if (f->left_pos < 0)
+ left = Fcons (Qplus, Fcons (make_number (f->left_pos), Qnil));
+ else
+ XSETINT (left, f->left_pos);
+ }
+ if (EQ (top, Qunbound))
+ {
+ top_no_change = 1;
+ if (f->top_pos < 0)
+ top = Fcons (Qplus, Fcons (make_number (f->top_pos), Qnil));
+ else
+ XSETINT (top, f->top_pos);
+ }
+
+ /* If one of the icon positions was not set, preserve or default it. */
+ if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
+ {
+ icon_left_no_change = 1;
+ icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
+ if (NILP (icon_left))
+ XSETINT (icon_left, 0);
+ }
+ if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
+ {
+ icon_top_no_change = 1;
+ icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
+ if (NILP (icon_top))
+ XSETINT (icon_top, 0);
+ }
+
+ if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
+ {
+ /* If the frame is visible already and the fullscreen parameter is
+ being set, it is too late to set WM manager hints to specify
+ size and position.
+ Here we first get the width, height and position that applies to
+ fullscreen. We then move the frame to the appropriate
+ position. Resize of the frame is taken care of in the code after
+ this if-statement. */
+ int new_left, new_top;
+
+ x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
+ if (new_top != f->top_pos || new_left != f->left_pos)
+ x_set_offset (f, new_left, new_top, 1);
+ }
+
+ /* Don't set these parameters unless they've been explicitly
+ specified. The window might be mapped or resized while we're in
+ this function, and we don't want to override that unless the lisp
+ code has asked for it.
+
+ Don't set these parameters unless they actually differ from the
+ window's current parameters; the window may not actually exist
+ yet. */
+ {
+ Lisp_Object frame;
+
+ check_frame_size (f, &height, &width);
+
+ XSETFRAME (frame, f);
+
+ if (width != FRAME_COLS (f)
+ || height != FRAME_LINES (f)
+ || f->new_text_lines || f->new_text_cols)
+ Fset_frame_size (frame, make_number (width), make_number (height));
+
+ if ((!NILP (left) || !NILP (top))
+ && ! (left_no_change && top_no_change)
+ && ! (NUMBERP (left) && XINT (left) == f->left_pos
+ && NUMBERP (top) && XINT (top) == f->top_pos))
+ {
+ int leftpos = 0;
+ int toppos = 0;
+
+ /* Record the signs. */
+ f->size_hint_flags &= ~ (XNegative | YNegative);
+ if (EQ (left, Qminus))
+ f->size_hint_flags |= XNegative;
+ else if (INTEGERP (left))
+ {
+ leftpos = XINT (left);
+ if (leftpos < 0)
+ f->size_hint_flags |= XNegative;
+ }
+ else if (CONSP (left) && EQ (XCAR (left), Qminus)
+ && CONSP (XCDR (left))
+ && INTEGERP (XCAR (XCDR (left))))
+ {
+ leftpos = - XINT (XCAR (XCDR (left)));
+ f->size_hint_flags |= XNegative;
+ }
+ else if (CONSP (left) && EQ (XCAR (left), Qplus)
+ && CONSP (XCDR (left))
+ && INTEGERP (XCAR (XCDR (left))))
+ {
+ leftpos = XINT (XCAR (XCDR (left)));
+ }
+
+ if (EQ (top, Qminus))
+ f->size_hint_flags |= YNegative;
+ else if (INTEGERP (top))
+ {
+ toppos = XINT (top);
+ if (toppos < 0)
+ f->size_hint_flags |= YNegative;
+ }
+ else if (CONSP (top) && EQ (XCAR (top), Qminus)
+ && CONSP (XCDR (top))
+ && INTEGERP (XCAR (XCDR (top))))
+ {
+ toppos = - XINT (XCAR (XCDR (top)));
+ f->size_hint_flags |= YNegative;
+ }
+ else if (CONSP (top) && EQ (XCAR (top), Qplus)
+ && CONSP (XCDR (top))
+ && INTEGERP (XCAR (XCDR (top))))
+ {
+ toppos = XINT (XCAR (XCDR (top)));
+ }
+
+
+ /* Store the numeric value of the position. */
+ f->top_pos = toppos;
+ f->left_pos = leftpos;
+
+ f->win_gravity = NorthWestGravity;
+
+ /* Actually set that position, and convert to absolute. */
+ x_set_offset (f, leftpos, toppos, -1);
+ }
+
+ if ((!NILP (icon_left) || !NILP (icon_top))
+ && ! (icon_left_no_change && icon_top_no_change))
+ x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
+ }
+
+ UNGCPRO;
+}
+
+
+/* Insert a description of internally-recorded parameters of frame X
+ into the parameter alist *ALISTPTR that is to be given to the user.
+ Only parameters that are specific to the X window system
+ and whose values are not correctly recorded in the frame's
+ param_alist need to be considered here. */
+
+void
+x_report_frame_params (f, alistptr)
+ struct frame *f;
+ Lisp_Object *alistptr;
+{
+ char buf[16];
+ Lisp_Object tem;
+
+ /* Represent negative positions (off the top or left screen edge)
+ in a way that Fmodify_frame_parameters will understand correctly. */
+ XSETINT (tem, f->left_pos);
+ if (f->left_pos >= 0)
+ store_in_alist (alistptr, Qleft, tem);
+ else
+ store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
+
+ XSETINT (tem, f->top_pos);
+ if (f->top_pos >= 0)
+ store_in_alist (alistptr, Qtop, tem);
+ else
+ store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
+
+ store_in_alist (alistptr, Qborder_width,
+ make_number (f->border_width));
+ store_in_alist (alistptr, Qinternal_border_width,
+ make_number (FRAME_INTERNAL_BORDER_WIDTH (f)));
+ store_in_alist (alistptr, Qleft_fringe,
+ make_number (FRAME_LEFT_FRINGE_WIDTH (f)));
+ store_in_alist (alistptr, Qright_fringe,
+ make_number (FRAME_RIGHT_FRINGE_WIDTH (f)));
+ store_in_alist (alistptr, Qscroll_bar_width,
+ (! FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+ ? make_number (0)
+ : FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0
+ ? make_number (FRAME_CONFIG_SCROLL_BAR_WIDTH (f))
+ /* nil means "use default width"
+ for non-toolkit scroll bar.
+ ruler-mode.el depends on this. */
+ : Qnil));
+ sprintf (buf, "%ld", (long) FRAME_X_WINDOW (f));
+ store_in_alist (alistptr, Qwindow_id,
+ build_string (buf));
+#ifdef HAVE_X_WINDOWS
+#ifdef USE_X_TOOLKIT
+ /* Tooltip frame may not have this widget. */
+ if (FRAME_X_OUTPUT (f)->widget)
+#endif
+ sprintf (buf, "%ld", (long) FRAME_OUTER_WINDOW (f));
+ store_in_alist (alistptr, Qouter_window_id,
+ build_string (buf));
+#endif
+ store_in_alist (alistptr, Qicon_name, f->icon_name);
+ FRAME_SAMPLE_VISIBILITY (f);
+ store_in_alist (alistptr, Qvisibility,
+ (FRAME_VISIBLE_P (f) ? Qt
+ : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
+ store_in_alist (alistptr, Qdisplay,
+ XCAR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
+
+ if (FRAME_X_OUTPUT (f)->parent_desc == FRAME_X_DISPLAY_INFO (f)->root_window)
+ tem = Qnil;
+ else
+ XSETFASTINT (tem, FRAME_X_OUTPUT (f)->parent_desc);
+ store_in_alist (alistptr, Qparent_id, tem);
+}
+
+
+/* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
+ the previous value of that parameter, NEW_VALUE is the new value. */
+
+void
+x_set_fullscreen (f, new_value, old_value)
+ struct frame *f;
+ Lisp_Object new_value, old_value;
+{
+ if (NILP (new_value))
+ f->want_fullscreen = FULLSCREEN_NONE;
+ else if (EQ (new_value, Qfullboth))
+ f->want_fullscreen = FULLSCREEN_BOTH;
+ else if (EQ (new_value, Qfullwidth))
+ f->want_fullscreen = FULLSCREEN_WIDTH;
+ else if (EQ (new_value, Qfullheight))
+ f->want_fullscreen = FULLSCREEN_HEIGHT;
+}
+
+
+/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
+ the previous value of that parameter, NEW_VALUE is the new value. */
+
+void
+x_set_line_spacing (f, new_value, old_value)
+ struct frame *f;
+ Lisp_Object new_value, old_value;
+{
+ if (NILP (new_value))
+ f->extra_line_spacing = 0;
+ else if (NATNUMP (new_value))
+ f->extra_line_spacing = XFASTINT (new_value);
+ else
+ signal_error ("Invalid line-spacing", new_value);
+ if (FRAME_VISIBLE_P (f))
+ redraw_frame (f);
+}
+
+
+/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
+ the previous value of that parameter, NEW_VALUE is the new value. */
+
+void
+x_set_screen_gamma (f, new_value, old_value)
+ struct frame *f;
+ Lisp_Object new_value, old_value;
+{
+ if (NILP (new_value))
+ f->gamma = 0;
+ else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
+ /* The value 0.4545 is the normal viewing gamma. */
+ f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
+ else
+ signal_error ("Invalid screen-gamma", new_value);
+
+ clear_face_cache (0);
+}
+
+
+void
+x_set_font (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ Lisp_Object result;
+ Lisp_Object fontset_name;
+ Lisp_Object frame;
+ int old_fontset = FRAME_FONTSET(f);
+
+ CHECK_STRING (arg);
+
+ fontset_name = Fquery_fontset (arg, Qnil);
+
+ BLOCK_INPUT;
+ result = (STRINGP (fontset_name)
+ ? x_new_fontset (f, SDATA (fontset_name))
+ : x_new_font (f, SDATA (arg)));
+ UNBLOCK_INPUT;
+
+ if (EQ (result, Qnil))
+ error ("Font `%s' is not defined", SDATA (arg));
+ else if (EQ (result, Qt))
+ error ("The characters of the given font have varying widths");
+ else if (STRINGP (result))
+ {
+ set_default_ascii_font (result);
+ if (STRINGP (fontset_name))
+ {
+ /* Fontset names are built from ASCII font names, so the
+ names may be equal despite there was a change. */
+ if (old_fontset == FRAME_FONTSET (f))
+ return;
+ }
+ else if (!NILP (Fequal (result, oldval)))
+ return;
+
+ /* Recalculate toolbar height. */
+ f->n_tool_bar_rows = 0;
+ /* Ensure we redraw it. */
+ clear_current_matrices (f);
+
+ store_frame_param (f, Qfont, result);
+ recompute_basic_faces (f);
+ }
+ else
+ abort ();
+
+ do_pending_window_change (0);
+
+ /* Don't call `face-set-after-frame-default' when faces haven't been
+ initialized yet. This is the case when called from
+ Fx_create_frame. In that case, the X widget or window doesn't
+ exist either, and we can end up in x_report_frame_params with a
+ null widget which gives a segfault. */
+ if (FRAME_FACE_CACHE (f))
+ {
+ XSETFRAME (frame, f);
+ call1 (Qface_set_after_frame_default, frame);
+ }
+}
+
+
+void
+x_set_fringe_width (f, new_value, old_value)
+ struct frame *f;
+ Lisp_Object new_value, old_value;
+{
+ compute_fringe_widths (f, 1);
+}
+
+void
+x_set_border_width (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ CHECK_NUMBER (arg);
+
+ if (XINT (arg) == f->border_width)
+ return;
+
+ if (FRAME_X_WINDOW (f) != 0)
+ error ("Cannot change the border width of a frame");
+
+ f->border_width = XINT (arg);
+}
+
+void
+x_set_internal_border_width (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ int old = FRAME_INTERNAL_BORDER_WIDTH (f);
+
+ CHECK_NUMBER (arg);
+ FRAME_INTERNAL_BORDER_WIDTH (f) = XINT (arg);
+ if (FRAME_INTERNAL_BORDER_WIDTH (f) < 0)
+ FRAME_INTERNAL_BORDER_WIDTH (f) = 0;
+
+#ifdef USE_X_TOOLKIT
+ if (FRAME_X_OUTPUT (f)->edit_widget)
+ widget_store_internal_border (FRAME_X_OUTPUT (f)->edit_widget);
+#endif
+
+ if (FRAME_INTERNAL_BORDER_WIDTH (f) == old)
+ return;
+
+ if (FRAME_X_WINDOW (f) != 0)
+ {
+ x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
+ SET_FRAME_GARBAGED (f);
+ do_pending_window_change (0);
+ }
+ else
+ SET_FRAME_GARBAGED (f);
+}
+
+void
+x_set_visibility (f, value, oldval)
+ struct frame *f;
+ Lisp_Object value, oldval;
+{
+ Lisp_Object frame;
+ XSETFRAME (frame, f);
+
+ if (NILP (value))
+ Fmake_frame_invisible (frame, Qt);
+ else if (EQ (value, Qicon))
+ Ficonify_frame (frame);
+ else
+ Fmake_frame_visible (frame);