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

« 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, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

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
}