emacsgtkfixed.c 7.42 KB
Newer Older
Paul Eggert's avatar
Paul Eggert committed
1
/* A Gtk Widget that inherits GtkFixed, but can be shrunk.
2
This file is only use when compiling with Gtk+ 3.
3

Paul Eggert's avatar
Paul Eggert committed
4
Copyright (C) 2011-2019 Free Software Foundation, Inc.
5 6 7 8 9

This file is part of GNU Emacs.

GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
10 11
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
12 13 14 15 16 17 18

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
19
along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
20

21
#include <config.h>
22

23 24 25
#include "lisp.h"
#include "frame.h"
#include "xterm.h"
Paul Eggert's avatar
Paul Eggert committed
26
#include "xwidget.h"
Joakim Verona's avatar
Joakim Verona committed
27 28
#include "emacsgtkfixed.h"

29
/* Silence a bogus diagnostic; see GNOME bug 683906.  */
30
#if GNUC_PREREQ (4, 7, 0) && ! GLIB_CHECK_VERSION (2, 35, 7)
31 32 33
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
34

35 36 37
typedef struct _EmacsFixed EmacsFixed;
typedef struct _EmacsFixedClass EmacsFixedClass;

38 39
struct _EmacsFixedPrivate
{
40
  struct frame *f;
41 42 43 44 45 46 47 48 49
};


static void emacs_fixed_get_preferred_width  (GtkWidget *widget,
                                              gint      *minimum,
                                              gint      *natural);
static void emacs_fixed_get_preferred_height (GtkWidget *widget,
                                              gint      *minimum,
                                              gint      *natural);
50
static GType emacs_fixed_get_type (void);
51 52
G_DEFINE_TYPE (EmacsFixed, emacs_fixed, GTK_TYPE_FIXED)

53 54 55 56 57 58 59
static EmacsFixed *
EMACS_FIXED (GtkWidget *widget)
{
  return G_TYPE_CHECK_INSTANCE_CAST (widget, emacs_fixed_get_type (),
				     EmacsFixed);
}

60 61
#ifdef HAVE_XWIDGETS

62 63 64 65 66 67 68
static EmacsFixedClass *
EMACS_FIXED_GET_CLASS (GtkWidget *widget)
{
  return G_TYPE_INSTANCE_GET_CLASS (widget, emacs_fixed_get_type (),
				    EmacsFixedClass);
}

69 70 71 72 73
struct GtkFixedPrivateL
{
  GList *children;
};

Paul Eggert's avatar
Paul Eggert committed
74 75 76
static void
emacs_fixed_gtk_widget_size_allocate (GtkWidget *widget,
				      GtkAllocation *allocation)
77
{
Paul Eggert's avatar
Paul Eggert committed
78
  /* For xwidgets.
79

Paul Eggert's avatar
Paul Eggert committed
80 81
     This basically re-implements the base class method and adds an
     additional case for an xwidget view.
82

Paul Eggert's avatar
Paul Eggert committed
83
     It would be nicer if the bse class method could be called first,
84
     and the xview modification only would remain here. It wasn't
Paul Eggert's avatar
Paul Eggert committed
85
     possible to solve it that way yet.  */
86 87
  EmacsFixedClass *klass;
  GtkWidgetClass *parent_class;
Paul Eggert's avatar
Paul Eggert committed
88
  struct GtkFixedPrivateL *priv;
89 90 91 92 93

  klass = EMACS_FIXED_GET_CLASS (widget);
  parent_class = g_type_class_peek_parent (klass);
  parent_class->size_allocate (widget, allocation);

Paul Eggert's avatar
Paul Eggert committed
94 95
  priv = G_TYPE_INSTANCE_GET_PRIVATE (widget, GTK_TYPE_FIXED,
				      struct GtkFixedPrivateL);
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145

  gtk_widget_set_allocation (widget, allocation);

  if (gtk_widget_get_has_window (widget))
    {
      if (gtk_widget_get_realized (widget))
        gdk_window_move_resize (gtk_widget_get_window (widget),
                                allocation->x,
                                allocation->y,
                                allocation->width,
                                allocation->height);
    }

  for (GList *children = priv->children; children; children = children->next)
    {
      GtkFixedChild *child = children->data;

      if (!gtk_widget_get_visible (child->widget))
        continue;

      GtkRequisition child_requisition;
      gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);

      GtkAllocation child_allocation;
      child_allocation.x = child->x;
      child_allocation.y = child->y;

      if (!gtk_widget_get_has_window (widget))
        {
          child_allocation.x += allocation->x;
          child_allocation.y += allocation->y;
        }

      child_allocation.width = child_requisition.width;
      child_allocation.height = child_requisition.height;

      struct xwidget_view *xv
        = g_object_get_data (G_OBJECT (child->widget), XG_XWIDGET_VIEW);
      if (xv)
        {
          child_allocation.width = xv->clip_right;
          child_allocation.height = xv->clip_bottom - xv->clip_top;
        }

      gtk_widget_size_allocate (child->widget, &child_allocation);
    }
}

#endif  /* HAVE_XWIDGETS */

146 147 148 149 150
static void
emacs_fixed_class_init (EmacsFixedClass *klass)
{
  GtkWidgetClass *widget_class;

151
  widget_class = (GtkWidgetClass *) klass;
152 153 154

  widget_class->get_preferred_width = emacs_fixed_get_preferred_width;
  widget_class->get_preferred_height = emacs_fixed_get_preferred_height;
155 156 157
#ifdef HAVE_XWIDGETS
  widget_class->size_allocate = emacs_fixed_gtk_widget_size_allocate;
#endif
158 159 160 161 162 163
  g_type_class_add_private (klass, sizeof (EmacsFixedPrivate));
}

static void
emacs_fixed_init (EmacsFixed *fixed)
{
164
  fixed->priv = G_TYPE_INSTANCE_GET_PRIVATE (fixed, emacs_fixed_get_type (),
165
                                             EmacsFixedPrivate);
166
  fixed->priv->f = 0;
167 168
}

Paul Eggert's avatar
Paul Eggert committed
169
GtkWidget *
170
emacs_fixed_new (struct frame *f)
171
{
172
  EmacsFixed *fixed = g_object_new (emacs_fixed_get_type (), NULL);
173 174 175
  EmacsFixedPrivate *priv = fixed->priv;
  priv->f = f;
  return GTK_WIDGET (fixed);
176 177 178 179 180 181 182 183 184
}

static void
emacs_fixed_get_preferred_width (GtkWidget *widget,
                                 gint      *minimum,
                                 gint      *natural)
{
  EmacsFixed *fixed = EMACS_FIXED (widget);
  EmacsFixedPrivate *priv = fixed->priv;
185 186 187
  int w = priv->f->output_data.x->size_hints.min_width;
  if (minimum) *minimum = w;
  if (natural) *natural = w;
188 189 190 191 192 193 194 195 196
}

static void
emacs_fixed_get_preferred_height (GtkWidget *widget,
                                  gint      *minimum,
                                  gint      *natural)
{
  EmacsFixed *fixed = EMACS_FIXED (widget);
  EmacsFixedPrivate *priv = fixed->priv;
197 198 199
  int h = priv->f->output_data.x->size_hints.min_height;
  if (minimum) *minimum = h;
  if (natural) *natural = h;
200 201
}

202 203 204 205 206

/* Override the X function so we can intercept Gtk+ 3 calls.
   Use our values for min_width/height so that KDE don't freak out
   (Bug#8919), and so users can resize our frames as they wish.  */

207
void
208
XSetWMSizeHints (Display *d,
Juanma Barranquero's avatar
Juanma Barranquero committed
209
                 Window w,
210
                 XSizeHints *hints,
Juanma Barranquero's avatar
Juanma Barranquero committed
211
                 Atom prop)
212
{
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
  struct x_display_info *dpyinfo = x_display_info_for_display (d);
  struct frame *f = x_top_window_to_frame (dpyinfo, w);
  long data[18];
  data[0] = hints->flags;
  data[1] = hints->x;
  data[2] = hints->y;
  data[3] = hints->width;
  data[4] = hints->height;
  data[5] = hints->min_width;
  data[6] = hints->min_height;
  data[7] = hints->max_width;
  data[8] = hints->max_height;
  data[9] = hints->width_inc;
  data[10] = hints->height_inc;
  data[11] = hints->min_aspect.x;
  data[12] = hints->min_aspect.y;
  data[13] = hints->max_aspect.x;
  data[14] = hints->max_aspect.y;
  data[15] = hints->base_width;
  data[16] = hints->base_height;
  data[17] = hints->win_gravity;

  if ((hints->flags & PMinSize) && f)
    {
      int w = f->output_data.x->size_hints.min_width;
      int h = f->output_data.x->size_hints.min_height;
      data[5] = w;
      data[6] = h;
    }

  XChangeProperty (d, w, prop, XA_WM_SIZE_HINTS, 32, PropModeReplace,
		   (unsigned char *) data, 18);
}
246

247 248 249
/* Override this X11 function.
   This function is in the same X11 file as the one above.  So we must
   provide it also.  */
Juanma Barranquero's avatar
Juanma Barranquero committed
250

251 252 253 254
void
XSetWMNormalHints (Display *d, Window w, XSizeHints *hints)
{
  XSetWMSizeHints (d, w, hints, XA_WM_NORMAL_HINTS);
255
}