~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to 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
 
}