gtkcols.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. /*
  2. * gtkcols.c - implementation of the `Columns' GTK layout container.
  3. */
  4. #include "gtkcols.h"
  5. static void columns_init(Columns *cols);
  6. static void columns_class_init(ColumnsClass *klass);
  7. static void columns_map(GtkWidget *widget);
  8. static void columns_unmap(GtkWidget *widget);
  9. static void columns_draw(GtkWidget *widget, GdkRectangle *area);
  10. static gint columns_expose(GtkWidget *widget, GdkEventExpose *event);
  11. static void columns_base_add(GtkContainer *container, GtkWidget *widget);
  12. static void columns_remove(GtkContainer *container, GtkWidget *widget);
  13. static void columns_forall(GtkContainer *container, gboolean include_internals,
  14. GtkCallback callback, gpointer callback_data);
  15. static gint columns_focus(GtkContainer *container, GtkDirectionType dir);
  16. static GtkType columns_child_type(GtkContainer *container);
  17. static void columns_size_request(GtkWidget *widget, GtkRequisition *req);
  18. static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc);
  19. static GtkContainerClass *parent_class = NULL;
  20. GtkType columns_get_type(void)
  21. {
  22. static GtkType columns_type = 0;
  23. if (!columns_type) {
  24. static const GtkTypeInfo columns_info = {
  25. "Columns",
  26. sizeof(Columns),
  27. sizeof(ColumnsClass),
  28. (GtkClassInitFunc) columns_class_init,
  29. (GtkObjectInitFunc) columns_init,
  30. /* reserved_1 */ NULL,
  31. /* reserved_2 */ NULL,
  32. (GtkClassInitFunc) NULL,
  33. };
  34. columns_type = gtk_type_unique(GTK_TYPE_CONTAINER, &columns_info);
  35. }
  36. return columns_type;
  37. }
  38. static gint (*columns_inherited_focus)(GtkContainer *container,
  39. GtkDirectionType direction);
  40. static void columns_class_init(ColumnsClass *klass)
  41. {
  42. GtkObjectClass *object_class;
  43. GtkWidgetClass *widget_class;
  44. GtkContainerClass *container_class;
  45. object_class = (GtkObjectClass *)klass;
  46. widget_class = (GtkWidgetClass *)klass;
  47. container_class = (GtkContainerClass *)klass;
  48. parent_class = gtk_type_class(GTK_TYPE_CONTAINER);
  49. /*
  50. * FIXME: do we have to do all this faffing with set_arg,
  51. * get_arg and child_arg_type? Ick.
  52. */
  53. widget_class->map = columns_map;
  54. widget_class->unmap = columns_unmap;
  55. widget_class->draw = columns_draw;
  56. widget_class->expose_event = columns_expose;
  57. widget_class->size_request = columns_size_request;
  58. widget_class->size_allocate = columns_size_allocate;
  59. container_class->add = columns_base_add;
  60. container_class->remove = columns_remove;
  61. container_class->forall = columns_forall;
  62. container_class->child_type = columns_child_type;
  63. /* Save the previous value of this method. */
  64. if (!columns_inherited_focus)
  65. columns_inherited_focus = container_class->focus;
  66. container_class->focus = columns_focus;
  67. }
  68. static void columns_init(Columns *cols)
  69. {
  70. GTK_WIDGET_SET_FLAGS(cols, GTK_NO_WINDOW);
  71. cols->children = NULL;
  72. cols->spacing = 0;
  73. }
  74. /*
  75. * These appear to be thoroughly tedious functions; the only reason
  76. * we have to reimplement them at all is because we defined our own
  77. * format for our GList of children...
  78. */
  79. static void columns_map(GtkWidget *widget)
  80. {
  81. Columns *cols;
  82. ColumnsChild *child;
  83. GList *children;
  84. g_return_if_fail(widget != NULL);
  85. g_return_if_fail(IS_COLUMNS(widget));
  86. cols = COLUMNS(widget);
  87. GTK_WIDGET_SET_FLAGS(cols, GTK_MAPPED);
  88. for (children = cols->children;
  89. children && (child = children->data);
  90. children = children->next) {
  91. if (child->widget &&
  92. GTK_WIDGET_VISIBLE(child->widget) &&
  93. !GTK_WIDGET_MAPPED(child->widget))
  94. gtk_widget_map(child->widget);
  95. }
  96. }
  97. static void columns_unmap(GtkWidget *widget)
  98. {
  99. Columns *cols;
  100. ColumnsChild *child;
  101. GList *children;
  102. g_return_if_fail(widget != NULL);
  103. g_return_if_fail(IS_COLUMNS(widget));
  104. cols = COLUMNS(widget);
  105. GTK_WIDGET_UNSET_FLAGS(cols, GTK_MAPPED);
  106. for (children = cols->children;
  107. children && (child = children->data);
  108. children = children->next) {
  109. if (child->widget &&
  110. GTK_WIDGET_VISIBLE(child->widget) &&
  111. GTK_WIDGET_MAPPED(child->widget))
  112. gtk_widget_unmap(child->widget);
  113. }
  114. }
  115. static void columns_draw(GtkWidget *widget, GdkRectangle *area)
  116. {
  117. Columns *cols;
  118. ColumnsChild *child;
  119. GList *children;
  120. GdkRectangle child_area;
  121. g_return_if_fail(widget != NULL);
  122. g_return_if_fail(IS_COLUMNS(widget));
  123. if (GTK_WIDGET_DRAWABLE(widget)) {
  124. cols = COLUMNS(widget);
  125. for (children = cols->children;
  126. children && (child = children->data);
  127. children = children->next) {
  128. if (child->widget &&
  129. GTK_WIDGET_DRAWABLE(child->widget) &&
  130. gtk_widget_intersect(child->widget, area, &child_area))
  131. gtk_widget_draw(child->widget, &child_area);
  132. }
  133. }
  134. }
  135. static gint columns_expose(GtkWidget *widget, GdkEventExpose *event)
  136. {
  137. Columns *cols;
  138. ColumnsChild *child;
  139. GList *children;
  140. GdkEventExpose child_event;
  141. g_return_val_if_fail(widget != NULL, FALSE);
  142. g_return_val_if_fail(IS_COLUMNS(widget), FALSE);
  143. g_return_val_if_fail(event != NULL, FALSE);
  144. if (GTK_WIDGET_DRAWABLE(widget)) {
  145. cols = COLUMNS(widget);
  146. child_event = *event;
  147. for (children = cols->children;
  148. children && (child = children->data);
  149. children = children->next) {
  150. if (child->widget &&
  151. GTK_WIDGET_DRAWABLE(child->widget) &&
  152. GTK_WIDGET_NO_WINDOW(child->widget) &&
  153. gtk_widget_intersect(child->widget, &event->area,
  154. &child_event.area))
  155. gtk_widget_event(child->widget, (GdkEvent *)&child_event);
  156. }
  157. }
  158. return FALSE;
  159. }
  160. static void columns_base_add(GtkContainer *container, GtkWidget *widget)
  161. {
  162. Columns *cols;
  163. g_return_if_fail(container != NULL);
  164. g_return_if_fail(IS_COLUMNS(container));
  165. g_return_if_fail(widget != NULL);
  166. cols = COLUMNS(container);
  167. /*
  168. * Default is to add a new widget spanning all columns.
  169. */
  170. columns_add(cols, widget, 0, 0); /* 0 means ncols */
  171. }
  172. static void columns_remove(GtkContainer *container, GtkWidget *widget)
  173. {
  174. Columns *cols;
  175. ColumnsChild *child;
  176. GtkWidget *childw;
  177. GList *children;
  178. gboolean was_visible;
  179. g_return_if_fail(container != NULL);
  180. g_return_if_fail(IS_COLUMNS(container));
  181. g_return_if_fail(widget != NULL);
  182. cols = COLUMNS(container);
  183. for (children = cols->children;
  184. children && (child = children->data);
  185. children = children->next) {
  186. if (child->widget != widget)
  187. continue;
  188. was_visible = GTK_WIDGET_VISIBLE(widget);
  189. gtk_widget_unparent(widget);
  190. cols->children = g_list_remove_link(cols->children, children);
  191. g_list_free(children);
  192. g_free(child);
  193. if (was_visible)
  194. gtk_widget_queue_resize(GTK_WIDGET(container));
  195. break;
  196. }
  197. for (children = cols->taborder;
  198. children && (childw = children->data);
  199. children = children->next) {
  200. if (childw != widget)
  201. continue;
  202. cols->taborder = g_list_remove_link(cols->taborder, children);
  203. g_list_free(children);
  204. break;
  205. }
  206. }
  207. static void columns_forall(GtkContainer *container, gboolean include_internals,
  208. GtkCallback callback, gpointer callback_data)
  209. {
  210. Columns *cols;
  211. ColumnsChild *child;
  212. GList *children, *next;
  213. g_return_if_fail(container != NULL);
  214. g_return_if_fail(IS_COLUMNS(container));
  215. g_return_if_fail(callback != NULL);
  216. cols = COLUMNS(container);
  217. for (children = cols->children;
  218. children && (child = children->data);
  219. children = next) {
  220. /*
  221. * We can't wait until after the callback to assign
  222. * `children = children->next', because the callback might
  223. * be gtk_widget_destroy, which would remove the link
  224. * `children' from the list! So instead we must get our
  225. * hands on the value of the `next' pointer _before_ the
  226. * callback.
  227. */
  228. next = children->next;
  229. if (child->widget)
  230. callback(child->widget, callback_data);
  231. }
  232. }
  233. static GtkType columns_child_type(GtkContainer *container)
  234. {
  235. return GTK_TYPE_WIDGET;
  236. }
  237. GtkWidget *columns_new(gint spacing)
  238. {
  239. Columns *cols;
  240. cols = gtk_type_new(columns_get_type());
  241. cols->spacing = spacing;
  242. return GTK_WIDGET(cols);
  243. }
  244. void columns_set_cols(Columns *cols, gint ncols, const gint *percentages)
  245. {
  246. ColumnsChild *childdata;
  247. gint i;
  248. g_return_if_fail(cols != NULL);
  249. g_return_if_fail(IS_COLUMNS(cols));
  250. g_return_if_fail(ncols > 0);
  251. g_return_if_fail(percentages != NULL);
  252. childdata = g_new(ColumnsChild, 1);
  253. childdata->widget = NULL;
  254. childdata->ncols = ncols;
  255. childdata->percentages = g_new(gint, ncols);
  256. childdata->force_left = FALSE;
  257. for (i = 0; i < ncols; i++)
  258. childdata->percentages[i] = percentages[i];
  259. cols->children = g_list_append(cols->children, childdata);
  260. }
  261. void columns_add(Columns *cols, GtkWidget *child,
  262. gint colstart, gint colspan)
  263. {
  264. ColumnsChild *childdata;
  265. g_return_if_fail(cols != NULL);
  266. g_return_if_fail(IS_COLUMNS(cols));
  267. g_return_if_fail(child != NULL);
  268. g_return_if_fail(child->parent == NULL);
  269. childdata = g_new(ColumnsChild, 1);
  270. childdata->widget = child;
  271. childdata->colstart = colstart;
  272. childdata->colspan = colspan;
  273. childdata->force_left = FALSE;
  274. cols->children = g_list_append(cols->children, childdata);
  275. cols->taborder = g_list_append(cols->taborder, child);
  276. gtk_widget_set_parent(child, GTK_WIDGET(cols));
  277. if (GTK_WIDGET_REALIZED(cols))
  278. gtk_widget_realize(child);
  279. if (GTK_WIDGET_VISIBLE(cols) && GTK_WIDGET_VISIBLE(child)) {
  280. if (GTK_WIDGET_MAPPED(cols))
  281. gtk_widget_map(child);
  282. gtk_widget_queue_resize(child);
  283. }
  284. }
  285. void columns_force_left_align(Columns *cols, GtkWidget *widget)
  286. {
  287. ColumnsChild *child;
  288. GList *children;
  289. g_return_if_fail(cols != NULL);
  290. g_return_if_fail(IS_COLUMNS(cols));
  291. g_return_if_fail(widget != NULL);
  292. for (children = cols->children;
  293. children && (child = children->data);
  294. children = children->next) {
  295. if (child->widget != widget)
  296. continue;
  297. child->force_left = TRUE;
  298. if (GTK_WIDGET_VISIBLE(widget))
  299. gtk_widget_queue_resize(GTK_WIDGET(cols));
  300. break;
  301. }
  302. }
  303. void columns_taborder_last(Columns *cols, GtkWidget *widget)
  304. {
  305. GtkWidget *childw;
  306. GList *children;
  307. g_return_if_fail(cols != NULL);
  308. g_return_if_fail(IS_COLUMNS(cols));
  309. g_return_if_fail(widget != NULL);
  310. for (children = cols->taborder;
  311. children && (childw = children->data);
  312. children = children->next) {
  313. if (childw != widget)
  314. continue;
  315. cols->taborder = g_list_remove_link(cols->taborder, children);
  316. g_list_free(children);
  317. cols->taborder = g_list_append(cols->taborder, widget);
  318. break;
  319. }
  320. }
  321. /*
  322. * Override GtkContainer's focus movement so the user can
  323. * explicitly specify the tab order.
  324. */
  325. static gint columns_focus(GtkContainer *container, GtkDirectionType dir)
  326. {
  327. Columns *cols;
  328. GList *pos;
  329. GtkWidget *focuschild;
  330. g_return_val_if_fail(container != NULL, FALSE);
  331. g_return_val_if_fail(IS_COLUMNS(container), FALSE);
  332. cols = COLUMNS(container);
  333. if (!GTK_WIDGET_DRAWABLE(cols) ||
  334. !GTK_WIDGET_IS_SENSITIVE(cols))
  335. return FALSE;
  336. if (!GTK_WIDGET_CAN_FOCUS(container) &&
  337. (dir == GTK_DIR_TAB_FORWARD || dir == GTK_DIR_TAB_BACKWARD)) {
  338. focuschild = container->focus_child;
  339. gtk_container_set_focus_child(container, NULL);
  340. if (dir == GTK_DIR_TAB_FORWARD)
  341. pos = cols->taborder;
  342. else
  343. pos = g_list_last(cols->taborder);
  344. while (pos) {
  345. GtkWidget *child = pos->data;
  346. if (focuschild) {
  347. if (focuschild == child) {
  348. focuschild = NULL; /* now we can start looking in here */
  349. if (GTK_WIDGET_DRAWABLE(child) &&
  350. GTK_IS_CONTAINER(child) &&
  351. !GTK_WIDGET_HAS_FOCUS(child)) {
  352. if (gtk_container_focus(GTK_CONTAINER(child), dir))
  353. return TRUE;
  354. }
  355. }
  356. } else if (GTK_WIDGET_DRAWABLE(child)) {
  357. if (GTK_IS_CONTAINER(child)) {
  358. if (gtk_container_focus(GTK_CONTAINER(child), dir))
  359. return TRUE;
  360. } else if (GTK_WIDGET_CAN_FOCUS(child)) {
  361. gtk_widget_grab_focus(child);
  362. return TRUE;
  363. }
  364. }
  365. if (dir == GTK_DIR_TAB_FORWARD)
  366. pos = pos->next;
  367. else
  368. pos = pos->prev;
  369. }
  370. return FALSE;
  371. } else
  372. return columns_inherited_focus(container, dir);
  373. }
  374. /*
  375. * Now here comes the interesting bit. The actual layout part is
  376. * done in the following two functions:
  377. *
  378. * columns_size_request() examines the list of widgets held in the
  379. * Columns, and returns a requisition stating the absolute minimum
  380. * size it can bear to be.
  381. *
  382. * columns_size_allocate() is given an allocation telling it what
  383. * size the whole container is going to be, and it calls
  384. * gtk_widget_size_allocate() on all of its (visible) children to
  385. * set their size and position relative to the top left of the
  386. * container.
  387. */
  388. static void columns_size_request(GtkWidget *widget, GtkRequisition *req)
  389. {
  390. Columns *cols;
  391. ColumnsChild *child;
  392. GList *children;
  393. gint i, ncols, colspan, *colypos;
  394. const gint *percentages;
  395. static const gint onecol[] = { 100 };
  396. g_return_if_fail(widget != NULL);
  397. g_return_if_fail(IS_COLUMNS(widget));
  398. g_return_if_fail(req != NULL);
  399. cols = COLUMNS(widget);
  400. req->width = 0;
  401. req->height = cols->spacing;
  402. ncols = 1;
  403. colypos = g_new(gint, 1);
  404. colypos[0] = 0;
  405. percentages = onecol;
  406. for (children = cols->children;
  407. children && (child = children->data);
  408. children = children->next) {
  409. GtkRequisition creq;
  410. if (!child->widget) {
  411. /* Column reconfiguration. */
  412. for (i = 1; i < ncols; i++) {
  413. if (colypos[0] < colypos[i])
  414. colypos[0] = colypos[i];
  415. }
  416. ncols = child->ncols;
  417. percentages = child->percentages;
  418. colypos = g_renew(gint, colypos, ncols);
  419. for (i = 1; i < ncols; i++)
  420. colypos[i] = colypos[0];
  421. continue;
  422. }
  423. /* Only take visible widgets into account. */
  424. if (!GTK_WIDGET_VISIBLE(child->widget))
  425. continue;
  426. gtk_widget_size_request(child->widget, &creq);
  427. colspan = child->colspan ? child->colspan : ncols-child->colstart;
  428. /*
  429. * To compute width: we know that creq.width plus
  430. * cols->spacing needs to equal a certain percentage of the
  431. * full width of the container. So we work this value out,
  432. * figure out how wide the container will need to be to
  433. * make that percentage of it equal to that width, and
  434. * ensure our returned width is at least that much. Very
  435. * simple really.
  436. */
  437. {
  438. int percent, thiswid, fullwid;
  439. percent = 0;
  440. for (i = 0; i < colspan; i++)
  441. percent += percentages[child->colstart+i];
  442. thiswid = creq.width + cols->spacing;
  443. /*
  444. * Since creq is the _minimum_ size the child needs, we
  445. * must ensure that it gets _at least_ that size.
  446. * Hence, when scaling thiswid up to fullwid, we must
  447. * round up, which means adding percent-1 before
  448. * dividing by percent.
  449. */
  450. fullwid = (thiswid * 100 + percent - 1) / percent;
  451. /*
  452. * The above calculation assumes every widget gets
  453. * cols->spacing on the right. So we subtract
  454. * cols->spacing here to account for the extra load of
  455. * spacing on the right.
  456. */
  457. if (req->width < fullwid - cols->spacing)
  458. req->width = fullwid - cols->spacing;
  459. }
  460. /*
  461. * To compute height: the widget's top will be positioned
  462. * at the largest y value so far reached in any of the
  463. * columns it crosses. Then it will go down by creq.height
  464. * plus padding; and the point it reaches at the bottom is
  465. * the new y value in all those columns, and minus the
  466. * padding it is also a lower bound on our own size
  467. * request.
  468. */
  469. {
  470. int topy, boty;
  471. topy = 0;
  472. for (i = 0; i < colspan; i++) {
  473. if (topy < colypos[child->colstart+i])
  474. topy = colypos[child->colstart+i];
  475. }
  476. boty = topy + creq.height + cols->spacing;
  477. for (i = 0; i < colspan; i++) {
  478. colypos[child->colstart+i] = boty;
  479. }
  480. if (req->height < boty - cols->spacing)
  481. req->height = boty - cols->spacing;
  482. }
  483. }
  484. req->width += 2*GTK_CONTAINER(cols)->border_width;
  485. req->height += 2*GTK_CONTAINER(cols)->border_width;
  486. g_free(colypos);
  487. }
  488. static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
  489. {
  490. Columns *cols;
  491. ColumnsChild *child;
  492. GList *children;
  493. gint i, ncols, colspan, border, *colxpos, *colypos;
  494. const gint *percentages;
  495. static const gint onecol[] = { 100 };
  496. g_return_if_fail(widget != NULL);
  497. g_return_if_fail(IS_COLUMNS(widget));
  498. g_return_if_fail(alloc != NULL);
  499. cols = COLUMNS(widget);
  500. widget->allocation = *alloc;
  501. border = GTK_CONTAINER(cols)->border_width;
  502. ncols = 1;
  503. percentages = onecol;
  504. /* colxpos gives the starting x position of each column.
  505. * We supply n+1 of them, so that we can find the RH edge easily.
  506. * All ending x positions are expected to be adjusted afterwards by
  507. * subtracting the spacing. */
  508. colxpos = g_new(gint, 2);
  509. colxpos[0] = 0;
  510. colxpos[1] = alloc->width - 2*border + cols->spacing;
  511. /* As in size_request, colypos is the lowest y reached in each column. */
  512. colypos = g_new(gint, 1);
  513. colypos[0] = 0;
  514. for (children = cols->children;
  515. children && (child = children->data);
  516. children = children->next) {
  517. GtkRequisition creq;
  518. GtkAllocation call;
  519. if (!child->widget) {
  520. gint percent;
  521. /* Column reconfiguration. */
  522. for (i = 1; i < ncols; i++) {
  523. if (colypos[0] < colypos[i])
  524. colypos[0] = colypos[i];
  525. }
  526. ncols = child->ncols;
  527. percentages = child->percentages;
  528. colypos = g_renew(gint, colypos, ncols);
  529. for (i = 1; i < ncols; i++)
  530. colypos[i] = colypos[0];
  531. colxpos = g_renew(gint, colxpos, ncols + 1);
  532. colxpos[0] = 0;
  533. percent = 0;
  534. for (i = 0; i < ncols; i++) {
  535. percent += percentages[i];
  536. colxpos[i+1] = (((alloc->width - 2*border) + cols->spacing)
  537. * percent / 100);
  538. }
  539. continue;
  540. }
  541. /* Only take visible widgets into account. */
  542. if (!GTK_WIDGET_VISIBLE(child->widget))
  543. continue;
  544. gtk_widget_get_child_requisition(child->widget, &creq);
  545. colspan = child->colspan ? child->colspan : ncols-child->colstart;
  546. /*
  547. * Starting x position is cols[colstart].
  548. * Ending x position is cols[colstart+colspan] - spacing.
  549. *
  550. * Unless we're forcing left, in which case the width is
  551. * exactly the requisition width.
  552. */
  553. call.x = alloc->x + border + colxpos[child->colstart];
  554. if (child->force_left)
  555. call.width = creq.width;
  556. else
  557. call.width = (colxpos[child->colstart+colspan] -
  558. colxpos[child->colstart] - cols->spacing);
  559. /*
  560. * To compute height: the widget's top will be positioned
  561. * at the largest y value so far reached in any of the
  562. * columns it crosses. Then it will go down by creq.height
  563. * plus padding; and the point it reaches at the bottom is
  564. * the new y value in all those columns.
  565. */
  566. {
  567. int topy, boty;
  568. topy = 0;
  569. for (i = 0; i < colspan; i++) {
  570. if (topy < colypos[child->colstart+i])
  571. topy = colypos[child->colstart+i];
  572. }
  573. call.y = alloc->y + border + topy;
  574. call.height = creq.height;
  575. boty = topy + creq.height + cols->spacing;
  576. for (i = 0; i < colspan; i++) {
  577. colypos[child->colstart+i] = boty;
  578. }
  579. }
  580. gtk_widget_size_allocate(child->widget, &call);
  581. }
  582. g_free(colxpos);
  583. g_free(colypos);
  584. }