~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to grub-core/gfxmenu/gui_box.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gui_box.c - GUI container that stack components. */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2008,2009  Free Software Foundation, Inc.
 
5
 *
 
6
 *  GRUB is free software: you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation, either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  GRUB is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <grub/mm.h>
 
21
#include <grub/misc.h>
 
22
#include <grub/gui.h>
 
23
#include <grub/gui_string_util.h>
 
24
 
 
25
struct component_node
 
26
{
 
27
  grub_gui_component_t component;
 
28
  struct component_node *next;
 
29
  struct component_node *prev;
 
30
};
 
31
 
 
32
typedef struct grub_gui_box *grub_gui_box_t;
 
33
 
 
34
typedef void (*layout_func_t) (grub_gui_box_t self, int modify_layout,
 
35
                               unsigned *minimal_width,
 
36
                               unsigned *minimal_height);
 
37
 
 
38
struct grub_gui_box
 
39
{
 
40
  struct grub_gui_container container;
 
41
 
 
42
  grub_gui_container_t parent;
 
43
  grub_video_rect_t bounds;
 
44
  char *id;
 
45
 
 
46
  /* Doubly linked list of components with dummy head & tail nodes.  */
 
47
  struct component_node chead;
 
48
  struct component_node ctail;
 
49
 
 
50
  /* The layout function: differs for vertical and horizontal boxes.  */
 
51
  layout_func_t layout_func;
 
52
};
 
53
 
 
54
static void
 
55
box_destroy (void *vself)
 
56
{
 
57
  grub_gui_box_t self = vself;
 
58
  struct component_node *cur;
 
59
  struct component_node *next;
 
60
  for (cur = self->chead.next; cur != &self->ctail; cur = next)
 
61
    {
 
62
      /* Copy the 'next' pointer, since we need it for the next iteration,
 
63
         and we're going to free the memory it is stored in.  */
 
64
      next = cur->next;
 
65
      /* Destroy the child component.  */
 
66
      cur->component->ops->destroy (cur->component);
 
67
      /* Free the linked list node.  */
 
68
      grub_free (cur);
 
69
    }
 
70
  grub_free (self);
 
71
}
 
72
 
 
73
static const char *
 
74
box_get_id (void *vself)
 
75
{
 
76
  grub_gui_box_t self = vself;
 
77
  return self->id;
 
78
}
 
79
 
 
80
static int
 
81
box_is_instance (void *vself __attribute__((unused)), const char *type)
 
82
{
 
83
  return (grub_strcmp (type, "component") == 0
 
84
          || grub_strcmp (type, "container") == 0);
 
85
}
 
86
 
 
87
static void
 
88
layout_horizontally (grub_gui_box_t self, int modify_layout,
 
89
                     unsigned *min_width, unsigned *min_height)
 
90
{
 
91
  /* Start at the left (chead) and set the x coordinates as we go right.  */
 
92
  /* All components have their width set to the box's width.  */
 
93
 
 
94
  struct component_node *cur;
 
95
  unsigned w = 0, mwfrac = 0, h = 0, x = 0;
 
96
  grub_fixed_signed_t wfrac = 0;
 
97
  int bogus_frac = 0;
 
98
 
 
99
  for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
 
100
    {
 
101
      grub_gui_component_t c = cur->component;
 
102
      unsigned mw = 0, mh = 0;
 
103
 
 
104
      if (c->ops->get_minimal_size)
 
105
        c->ops->get_minimal_size (c, &mw, &mh);
 
106
 
 
107
      if (c->h > (signed) h)
 
108
        h = c->h;
 
109
      if (mh > h)
 
110
        h = mh;
 
111
      wfrac += c->wfrac;
 
112
      w += c->w;
 
113
      if (mw - c->w > 0)
 
114
        mwfrac += mw - c->w;
 
115
    }
 
116
  if (wfrac > GRUB_FIXED_1 || (w > 0 && wfrac == GRUB_FIXED_1))
 
117
    bogus_frac = 1;
 
118
 
 
119
  if (min_width)
 
120
    {
 
121
      if (wfrac < GRUB_FIXED_1)
 
122
        *min_width = grub_fixed_sfs_divide (w, GRUB_FIXED_1 - wfrac);
 
123
      else
 
124
        *min_width = w;
 
125
      if (*min_width < w + mwfrac)
 
126
        *min_width = w + mwfrac;
 
127
    }
 
128
  if (min_height)
 
129
    *min_height = h;
 
130
 
 
131
  if (!modify_layout)
 
132
    return;
 
133
 
 
134
  for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
 
135
    {
 
136
      grub_video_rect_t r;
 
137
      grub_gui_component_t c = cur->component;
 
138
      unsigned mw = 0, mh = 0;
 
139
 
 
140
      r.x = x;
 
141
      r.y = 0;
 
142
      r.height = h;
 
143
 
 
144
      if (c->ops->get_minimal_size)
 
145
        c->ops->get_minimal_size (c, &mw, &mh);
 
146
 
 
147
      r.width = c->w;
 
148
      if (!bogus_frac)
 
149
        r.width += grub_fixed_sfs_multiply (self->bounds.width, c->wfrac);
 
150
 
 
151
      if (r.width < mw)
 
152
        r.width = mw;
 
153
 
 
154
      c->ops->set_bounds (c, &r);
 
155
 
 
156
      x += r.width;
 
157
    }
 
158
}
 
159
 
 
160
static void
 
161
layout_vertically (grub_gui_box_t self, int modify_layout,
 
162
                     unsigned *min_width, unsigned *min_height)
 
163
{
 
164
  /* Start at the top (chead) and set the y coordinates as we go rdown.  */
 
165
  /* All components have their height set to the box's height.  */
 
166
 
 
167
  struct component_node *cur;
 
168
  unsigned h = 0, mhfrac = 0, w = 0, y = 0;
 
169
  grub_fixed_signed_t hfrac = 0;
 
170
  int bogus_frac = 0;
 
171
 
 
172
  for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
 
173
    {
 
174
      grub_gui_component_t c = cur->component;
 
175
      unsigned mw = 0, mh = 0;
 
176
 
 
177
      if (c->ops->get_minimal_size)
 
178
        c->ops->get_minimal_size (c, &mw, &mh);
 
179
 
 
180
      if (c->w > (signed) w)
 
181
        w = c->w;
 
182
      if (mw > w)
 
183
        w = mw;
 
184
      hfrac += c->hfrac;
 
185
      h += c->h;
 
186
      if (mh - c->h > 0)
 
187
        mhfrac += mh - c->h;
 
188
    }
 
189
  if (hfrac > GRUB_FIXED_1 || (h > 0 && hfrac == GRUB_FIXED_1))
 
190
    bogus_frac = 1;
 
191
 
 
192
  if (min_height)
 
193
    {
 
194
      if (hfrac < GRUB_FIXED_1)
 
195
        *min_height = grub_fixed_sfs_divide (h, GRUB_FIXED_1 - hfrac);
 
196
      else
 
197
        *min_height = h;
 
198
      if (*min_height < h + mhfrac)
 
199
        *min_height = h + mhfrac;
 
200
    }
 
201
  if (min_width)
 
202
    *min_width = w;
 
203
 
 
204
  if (!modify_layout)
 
205
    return;
 
206
 
 
207
  for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
 
208
    {
 
209
      grub_video_rect_t r;
 
210
      grub_gui_component_t c = cur->component;
 
211
      unsigned mw = 0, mh = 0;
 
212
 
 
213
      r.x = 0;
 
214
      r.y = y;
 
215
      r.width = w;
 
216
 
 
217
      if (c->ops->get_minimal_size)
 
218
        c->ops->get_minimal_size (c, &mw, &mh);
 
219
 
 
220
      r.height = c->h;
 
221
      if (!bogus_frac)
 
222
        r.height += grub_fixed_sfs_multiply (self->bounds.height, c->hfrac);
 
223
 
 
224
      if (r.height < mh)
 
225
        r.height = mh;
 
226
 
 
227
      c->ops->set_bounds (c, &r);
 
228
 
 
229
      y += r.height;
 
230
    }
 
231
}
 
232
 
 
233
static void
 
234
box_paint (void *vself, const grub_video_rect_t *region)
 
235
{
 
236
  grub_gui_box_t self = vself;
 
237
  struct component_node *cur;
 
238
  grub_video_rect_t vpsave;
 
239
 
 
240
  grub_gui_set_viewport (&self->bounds, &vpsave);
 
241
  for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
 
242
    {
 
243
      grub_gui_component_t comp = cur->component;
 
244
      comp->ops->paint (comp, region);
 
245
    }
 
246
  grub_gui_restore_viewport (&vpsave);
 
247
}
 
248
 
 
249
static void
 
250
box_set_parent (void *vself, grub_gui_container_t parent)
 
251
{
 
252
  grub_gui_box_t self = vself;
 
253
  self->parent = parent;
 
254
}
 
255
 
 
256
static grub_gui_container_t
 
257
box_get_parent (void *vself)
 
258
{
 
259
  grub_gui_box_t self = vself;
 
260
  return self->parent;
 
261
}
 
262
 
 
263
static void
 
264
box_set_bounds (void *vself, const grub_video_rect_t *bounds)
 
265
{
 
266
  grub_gui_box_t self = vself;
 
267
  self->bounds = *bounds;
 
268
  self->layout_func (self, 1, 0, 0);   /* Relayout the children.  */
 
269
}
 
270
 
 
271
static void
 
272
box_get_bounds (void *vself, grub_video_rect_t *bounds)
 
273
{
 
274
  grub_gui_box_t self = vself;
 
275
  *bounds = self->bounds;
 
276
}
 
277
 
 
278
/* The box's preferred size is based on the preferred sizes
 
279
   of its children.  */
 
280
static void
 
281
box_get_minimal_size (void *vself, unsigned *width, unsigned *height)
 
282
{
 
283
  grub_gui_box_t self = vself;
 
284
  self->layout_func (self, 0, width, height);   /* Just calculate the size.  */
 
285
}
 
286
 
 
287
static grub_err_t
 
288
box_set_property (void *vself, const char *name, const char *value)
 
289
{
 
290
  grub_gui_box_t self = vself;
 
291
  if (grub_strcmp (name, "id") == 0)
 
292
    {
 
293
      grub_free (self->id);
 
294
      if (value)
 
295
        {
 
296
          self->id = grub_strdup (value);
 
297
          if (! self->id)
 
298
            return grub_errno;
 
299
        }
 
300
      else
 
301
        self->id = 0;
 
302
    }
 
303
 
 
304
  return grub_errno;
 
305
}
 
306
 
 
307
static void
 
308
box_add (void *vself, grub_gui_component_t comp)
 
309
{
 
310
  grub_gui_box_t self = vself;
 
311
  struct component_node *node;
 
312
  node = grub_malloc (sizeof (*node));
 
313
  if (! node)
 
314
    return;   /* Note: probably should handle the error.  */
 
315
  node->component = comp;
 
316
  /* Insert the node before the tail.  */
 
317
  node->prev = self->ctail.prev;
 
318
  node->prev->next = node;
 
319
  node->next = &self->ctail;
 
320
  node->next->prev = node;
 
321
 
 
322
  comp->ops->set_parent (comp, (grub_gui_container_t) self);
 
323
  self->layout_func (self, 1, 0, 0);   /* Relayout the children.  */
 
324
}
 
325
 
 
326
static void
 
327
box_remove (void *vself, grub_gui_component_t comp)
 
328
{
 
329
  grub_gui_box_t self = vself;
 
330
  struct component_node *cur;
 
331
  for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
 
332
    {
 
333
      if (cur->component == comp)
 
334
        {
 
335
          /* Unlink 'cur' from the list.  */
 
336
          cur->prev->next = cur->next;
 
337
          cur->next->prev = cur->prev;
 
338
          /* Free the node's memory (but don't destroy the component).  */
 
339
          grub_free (cur);
 
340
          /* Must not loop again, since 'cur' would be dereferenced!  */
 
341
          return;
 
342
        }
 
343
    }
 
344
}
 
345
 
 
346
static void
 
347
box_iterate_children (void *vself,
 
348
                      grub_gui_component_callback cb, void *userdata)
 
349
{
 
350
  grub_gui_box_t self = vself;
 
351
  struct component_node *cur;
 
352
  for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
 
353
    cb (cur->component, userdata);
 
354
}
 
355
 
 
356
static struct grub_gui_component_ops box_comp_ops =
 
357
  {
 
358
    .destroy = box_destroy,
 
359
    .get_id = box_get_id,
 
360
    .is_instance = box_is_instance,
 
361
    .paint = box_paint,
 
362
    .set_parent = box_set_parent,
 
363
    .get_parent = box_get_parent,
 
364
    .set_bounds = box_set_bounds,
 
365
    .get_bounds = box_get_bounds,
 
366
    .get_minimal_size = box_get_minimal_size,
 
367
    .set_property = box_set_property
 
368
  };
 
369
 
 
370
static struct grub_gui_container_ops box_ops =
 
371
{
 
372
  .add = box_add,
 
373
  .remove = box_remove,
 
374
  .iterate_children = box_iterate_children
 
375
};
 
376
 
 
377
/* Box constructor.  Specify the appropriate layout function to create
 
378
   a horizontal or vertical stacking box.  */
 
379
static grub_gui_box_t
 
380
box_new (layout_func_t layout_func)
 
381
{
 
382
  grub_gui_box_t box;
 
383
  box = grub_zalloc (sizeof (*box));
 
384
  if (! box)
 
385
    return 0;
 
386
  box->container.ops = &box_ops;
 
387
  box->container.component.ops = &box_comp_ops;
 
388
  box->chead.next = &box->ctail;
 
389
  box->ctail.prev = &box->chead;
 
390
  box->layout_func = layout_func;
 
391
  return box;
 
392
}
 
393
 
 
394
/* Create a new container that stacks its child components horizontally,
 
395
   from left to right.  Each child get a width corresponding to its
 
396
   preferred width.  The height of each child is set the maximum of the
 
397
   preferred heights of all children.  */
 
398
grub_gui_container_t
 
399
grub_gui_hbox_new (void)
 
400
{
 
401
  return (grub_gui_container_t) box_new (layout_horizontally);
 
402
}
 
403
 
 
404
/* Create a new container that stacks its child components verticallyj,
 
405
   from top to bottom.  Each child get a height corresponding to its
 
406
   preferred height.  The width of each child is set the maximum of the
 
407
   preferred widths of all children.  */
 
408
grub_gui_container_t
 
409
grub_gui_vbox_new (void)
 
410
{
 
411
  return (grub_gui_container_t) box_new (layout_vertically);
 
412
}