x3gtk.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include "x3.h"
  4. #include "x3common.h"
  5. void x3init(int *pargc, char ***pargv)
  6. {
  7. gtk_init(pargc, pargv);
  8. x3initqs();
  9. }
  10. static void
  11. x3_getfirst_callback(GtkWidget *widget, gpointer data)
  12. {
  13. GtkWidget **pwidget = (GtkWidget **)data;
  14. if (*pwidget == NULL)
  15. *pwidget = widget;
  16. }
  17. static GtkWidget *x3_gtkwidget_getchild(GtkWidget *w)
  18. {
  19. GtkWidget *child = NULL;
  20. gtk_container_foreach(GTK_CONTAINER(w),
  21. x3_getfirst_callback,
  22. (gpointer)&child);
  23. return child;
  24. }
  25. typedef struct {
  26. x3widget base;
  27. gboolean expand;
  28. gboolean fill;
  29. guint padding;
  30. } x3widget_box;
  31. static void x3widget_init(x3widget *w, x3widget *parent, char *name,
  32. GtkWidget *widget)
  33. {
  34. w->name = g_strdup(name);
  35. w->widget = widget;
  36. w->parent = parent;
  37. if (parent) {
  38. if (GTK_IS_WINDOW(parent->widget)) {
  39. GtkWidget *vbox = x3_gtkwidget_getchild(parent->widget);
  40. if (GTK_IS_MENU_ITEM(widget)) {
  41. GtkWidget *first_child = x3_gtkwidget_getchild(vbox);
  42. GtkWidget *menubar;
  43. if (first_child == NULL || !GTK_IS_MENU_BAR(first_child)) {
  44. menubar = gtk_menu_bar_new();
  45. gtk_box_pack_start(GTK_BOX(vbox), menubar,
  46. FALSE, FALSE, 0);
  47. gtk_widget_show(menubar);
  48. } else
  49. menubar = first_child;
  50. gtk_menu_bar_append(GTK_MENU_BAR(menubar), widget);
  51. } else {
  52. gtk_container_add(GTK_CONTAINER(vbox), widget);
  53. }
  54. } else if (GTK_IS_MENU_ITEM(parent->widget)) {
  55. GtkWidget *menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(parent->widget));
  56. gtk_menu_shell_append(GTK_MENU_SHELL(menu), widget);
  57. } else if (GTK_IS_BOX(parent->widget)) {
  58. x3widget_box *pwb = (x3widget_box *)parent;
  59. gtk_box_pack_start(GTK_BOX(parent->widget), widget,
  60. pwb->expand, pwb->fill, pwb->padding);
  61. } else {
  62. gtk_container_add(GTK_CONTAINER(parent->widget), widget);
  63. }
  64. }
  65. }
  66. static x3widget *x3widget_new(x3widget *parent, char *name, GtkWidget *widget)
  67. {
  68. x3widget *result = (x3widget *)malloc(sizeof(x3widget));
  69. x3widget_init(result, parent, name, widget);
  70. return result;
  71. }
  72. static x3widget *x3box_new(x3widget *parent, GtkWidget *widget)
  73. {
  74. x3widget_box *result = (x3widget_box *)malloc(sizeof(x3widget_box));
  75. x3widget_init(&result->base, parent, NULL, widget);
  76. result->expand = TRUE;
  77. result->fill = TRUE;
  78. result->padding = 0;
  79. return &result->base;
  80. }
  81. void x3_window_show(x3widget *w)
  82. {
  83. gtk_widget_show(w->widget);
  84. }
  85. void x3window_setdefaultsize(x3widget *w, int width, int height)
  86. {
  87. gtk_window_set_default_size(GTK_WINDOW(w->widget), width, height);
  88. }
  89. void x3main(void)
  90. {
  91. x3sync();
  92. gtk_main();
  93. }
  94. /* some constructors */
  95. typedef struct {
  96. x3widget base;
  97. x3window_callback callback;
  98. void *callback_data;
  99. GtkAccelGroup *accel_group;
  100. } x3widget_window;
  101. gboolean x3window_delete(GtkWidget *window, GdkEvent *event, gpointer data)
  102. {
  103. /* todo: pass this as a command callback */
  104. if (--x3n_winopen <= 0)
  105. gtk_main_quit();
  106. return FALSE;
  107. }
  108. x3widget *x3window(x3windowflags flags, char *label,
  109. x3window_callback callback, void *callback_data)
  110. {
  111. GtkWidget *window;
  112. GtkWidget *vbox;
  113. x3widget_window *result;
  114. window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  115. gtk_window_set_title(GTK_WINDOW(window), label);
  116. vbox = gtk_vbox_new(FALSE, 0);
  117. gtk_widget_show(vbox);
  118. gtk_container_add(GTK_CONTAINER(window), vbox);
  119. result = (x3widget_window *)malloc(sizeof(x3widget_window));
  120. x3widget_init(&result->base, NULL, "mainwin", window);
  121. result->callback = callback;
  122. result->callback_data = callback_data;
  123. result->accel_group = gtk_accel_group_new();
  124. gtk_window_add_accel_group(GTK_WINDOW(window), result->accel_group);
  125. g_signal_connect(G_OBJECT(window), "delete-event",
  126. G_CALLBACK(x3window_delete), result);
  127. x3qshow(&result->base);
  128. x3n_winopen++;
  129. return &result->base;
  130. }
  131. x3widget *x3menu(x3widget *parent, char *name)
  132. {
  133. GtkWidget *item;
  134. GtkWidget *menu;
  135. menu = gtk_menu_new();
  136. item = gtk_menu_item_new_with_label(name);
  137. gtk_widget_show(item);
  138. gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
  139. return x3widget_new(parent, NULL, item);
  140. }
  141. typedef struct {
  142. x3widget base;
  143. char *cmd;
  144. } x3widget_cmdable;
  145. static void x3doevent(x3widget_cmdable *wc, char *str)
  146. {
  147. char *cmd = wc->cmd;
  148. x3widget *w = &wc->base;
  149. x3widget_window *ww;
  150. while (w->parent) w = w->parent;
  151. ww = (x3widget_window *)w;
  152. ww->callback(w, ww->callback_data, cmd, str, NULL, NULL);
  153. x3sync();
  154. }
  155. static void x3cmdable_clicked(GtkWidget *widget, gpointer data)
  156. {
  157. x3widget_cmdable *wc = (x3widget_cmdable *)data;
  158. x3doevent(wc, "command");
  159. }
  160. static const char *asciinames[] = {
  161. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  162. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  163. "space",
  164. "exclam",
  165. "quotedbl",
  166. "numbersign",
  167. "dollar",
  168. "percent",
  169. "ampersand",
  170. "apostrophe",
  171. "parenleft",
  172. "parenright",
  173. "asterisk",
  174. "plus",
  175. "comma",
  176. "minus",
  177. "period",
  178. "slash",
  179. "0",
  180. "1",
  181. "2",
  182. "3",
  183. "4",
  184. "5",
  185. "6",
  186. "7",
  187. "8",
  188. "9",
  189. "colon",
  190. "semicolon",
  191. "less",
  192. "equal",
  193. "greater",
  194. "question",
  195. "at",
  196. "<shift>a",
  197. "<shift>b",
  198. "<shift>c",
  199. "<shift>d",
  200. "<shift>e",
  201. "<shift>f",
  202. "<shift>g",
  203. "<shift>h",
  204. "<shift>i",
  205. "<shift>j",
  206. "<shift>k",
  207. "<shift>l",
  208. "<shift>m",
  209. "<shift>n",
  210. "<shift>o",
  211. "<shift>p",
  212. "<shift>q",
  213. "<shift>r",
  214. "<shift>s",
  215. "<shift>t",
  216. "<shift>u",
  217. "<shift>v",
  218. "<shift>w",
  219. "<shift>x",
  220. "<shift>y",
  221. "<shift>z",
  222. "bracketleft",
  223. "backslash",
  224. "bracketright",
  225. "asciicircum",
  226. "underscore",
  227. "grave",
  228. "a",
  229. "b",
  230. "c",
  231. "d",
  232. "e",
  233. "f",
  234. "g",
  235. "h",
  236. "i",
  237. "j",
  238. "k",
  239. "l",
  240. "m",
  241. "n",
  242. "o",
  243. "p",
  244. "q",
  245. "r",
  246. "s",
  247. "t",
  248. "u",
  249. "v",
  250. "w",
  251. "x",
  252. "y",
  253. "z",
  254. "braceleft",
  255. "bar",
  256. "braceright",
  257. "asciitilde"
  258. };
  259. /* return 1 on success */
  260. static int
  261. x3parseshortcut(const char *shortcut,
  262. guint *accelerator_key, GdkModifierType *accelerator_mods)
  263. {
  264. int len;
  265. char tmp[256];
  266. int i;
  267. if (shortcut == NULL) return 0;
  268. len = strlen(shortcut);
  269. if (len >= sizeof(tmp) - 1) return 0;
  270. strcpy(tmp, shortcut);
  271. for (i = 0; i < len - 5; i++)
  272. if (!memcmp(tmp + i, "<cmd>", 5))
  273. memcpy(tmp + i, "<ctl>", 5);
  274. if (len == 1 || tmp[len - 2] == '>') {
  275. unsigned char c = (unsigned char)tmp[len-1];
  276. if (c < sizeof(asciinames) / sizeof(asciinames[0]) && asciinames[c] &&
  277. len + strlen(asciinames[c]) < sizeof(tmp))
  278. strcpy(tmp + len - 1, asciinames[c]);
  279. }
  280. gtk_accelerator_parse(tmp, accelerator_key, accelerator_mods);
  281. return *accelerator_key != 0 || *accelerator_mods != 0;
  282. }
  283. static GtkAccelGroup *
  284. x3getaccelgroup(x3widget *w)
  285. {
  286. while (w->parent) w = w->parent;
  287. if (!GTK_IS_WINDOW(w->widget)) return NULL;
  288. return ((x3widget_window *)w)->accel_group;
  289. }
  290. x3widget *x3menuitem(x3widget *parent, char *name, char *cmd, char *shortcut)
  291. {
  292. GtkWidget *item;
  293. x3widget_cmdable *result = (x3widget_cmdable *)malloc(sizeof(x3widget_cmdable));
  294. guint accel_key;
  295. GdkModifierType accel_mods;
  296. item = gtk_menu_item_new_with_label(name);
  297. x3widget_init(&result->base, parent, cmd, item);
  298. result->cmd = g_strdup(cmd);
  299. g_signal_connect(G_OBJECT(item), "activate",
  300. G_CALLBACK(x3cmdable_clicked), result);
  301. if (x3parseshortcut(shortcut, &accel_key, &accel_mods)) {
  302. gtk_widget_add_accelerator(item, "activate", x3getaccelgroup(parent),
  303. accel_key, accel_mods, GTK_ACCEL_VISIBLE);
  304. }
  305. gtk_widget_show(item);
  306. return &result->base;
  307. }
  308. x3widget *x3menusep(x3widget *parent)
  309. {
  310. GtkWidget *item;
  311. item = gtk_separator_menu_item_new();
  312. gtk_widget_show(item);
  313. return x3widget_new(parent, NULL, item);
  314. }
  315. x3widget *x3vbox(x3widget *parent, int homogeneous, int spacing)
  316. {
  317. GtkWidget *vbox = gtk_vbox_new(homogeneous, spacing);
  318. gtk_widget_show(vbox);
  319. return x3box_new(parent, vbox);
  320. }
  321. x3widget *x3hpane(x3widget *parent)
  322. {
  323. GtkWidget *hpane = gtk_hpaned_new();
  324. gtk_widget_show(hpane);
  325. return x3widget_new(parent, NULL, hpane);
  326. }
  327. x3widget *x3vpane(x3widget *parent)
  328. {
  329. GtkWidget *vpane = gtk_vpaned_new();
  330. gtk_widget_show(vpane);
  331. return x3widget_new(parent, NULL, vpane);
  332. }
  333. x3widget *x3align(x3widget *parent, x3alignment alignment)
  334. {
  335. int xa = alignment & 3;
  336. int ya = (alignment >> 2) & 3;
  337. float xalign = .5 * (1 + (xa >> 1) - (xa & 1));
  338. float yalign = .5 * (1 + (ya >> 1) - (ya & 1));
  339. float xscale = (xa == 3);
  340. float yscale = (ya == 3);
  341. GtkWidget *align = gtk_alignment_new(xalign, yalign, xscale, yscale);
  342. gtk_widget_show(align);
  343. return x3widget_new(parent, NULL, align);
  344. }
  345. x3widget *x3pad(x3widget *parent, int t, int b, int l, int r)
  346. {
  347. GtkWidget *align = gtk_alignment_new(0, 0, 1, 1);
  348. gtk_alignment_set_padding(GTK_ALIGNMENT(align), t, b, l, r);
  349. gtk_widget_show(align);
  350. return x3widget_new(parent, NULL, align);
  351. }
  352. x3widget *x3button(x3widget *parent, char *cmd, char *label)
  353. {
  354. GtkWidget *button = gtk_button_new_with_label(label);
  355. x3widget_cmdable *result = (x3widget_cmdable *)malloc(sizeof(x3widget_cmdable));
  356. x3widget_init(&result->base, parent, cmd, button);
  357. result->cmd = g_strdup(cmd);
  358. g_signal_connect(G_OBJECT(button), "clicked",
  359. G_CALLBACK(x3cmdable_clicked), result);
  360. gtk_widget_show(button);
  361. return &result->base;
  362. }
  363. x3widget *x3label(x3widget *parent, char *text)
  364. {
  365. GtkWidget *label = gtk_label_new(text);
  366. gtk_widget_show(label);
  367. return x3widget_new(parent, NULL, label);
  368. }
  369. x3widget *x3edittext(x3widget *parent, char *cmd)
  370. {
  371. GtkWidget *entry = gtk_entry_new();
  372. gtk_widget_show(entry);
  373. return x3widget_new(parent, cmd, entry);
  374. }
  375. typedef struct {
  376. x3widget base;
  377. x3viewflags flags;
  378. x3viewclient *vc;
  379. } x3widget_view;
  380. static gboolean x3view_expose(GtkWidget *widget, GdkEventExpose *event,
  381. gpointer data)
  382. {
  383. x3widget_view *w = (x3widget_view *)data;
  384. GdkWindow *window = GTK_IS_LAYOUT(widget) ?
  385. GTK_LAYOUT(widget)->bin_window :
  386. widget->window;
  387. if (w->vc && w->vc->draw) {
  388. x3dc dc;
  389. dc.x = event->area.x;
  390. dc.y = event->area.y;
  391. dc.width = event->area.width;
  392. dc.height = event->area.height;
  393. if (w->flags & x3view_rgb) {
  394. dc.rowstride = (event->area.width * 3 + 3) & -4;
  395. dc.buf = (guchar *)malloc(event->area.height * dc.rowstride);
  396. dc.cr = NULL;
  397. w->vc->draw(w->vc, &dc);
  398. gdk_draw_rgb_image(window, widget->style->black_gc,
  399. event->area.x, event->area.y,
  400. event->area.width, event->area.height,
  401. GDK_RGB_DITHER_NORMAL,
  402. dc.buf, dc.rowstride);
  403. free(dc.buf);
  404. } else if (w->flags & x3view_2d) {
  405. dc.cr = gdk_cairo_create(window);
  406. dc.buf = NULL;
  407. w->vc->draw(w->vc, &dc);
  408. cairo_destroy(dc.cr);
  409. }
  410. }
  411. #if 1
  412. /* experimental code for managing cairo dynamics */
  413. if (event->count == 0)
  414. gdk_flush();
  415. #endif
  416. return TRUE;
  417. }
  418. static gboolean x3view_button_press(GtkWidget *widget, GdkEventButton *event,
  419. gpointer data)
  420. {
  421. x3widget_view *w = (x3widget_view *)data;
  422. guint button = event->button;
  423. if (event->type == GDK_BUTTON_RELEASE) button = -button;
  424. if (w->vc && w->vc->mouse) {
  425. w->vc->mouse(w->vc, button, event->state, event->x, event->y);
  426. return TRUE;
  427. }
  428. x3sync();
  429. return FALSE;
  430. }
  431. static gboolean x3view_pointer_motion(GtkWidget *widget, GdkEventButton *event,
  432. gpointer data)
  433. {
  434. x3widget_view *w = (x3widget_view *)data;
  435. if (w->vc && w->vc->mouse) {
  436. w->vc->mouse(w->vc, 0, event->state,
  437. event->x, event->y);
  438. return TRUE;
  439. }
  440. x3sync();
  441. return FALSE;
  442. }
  443. static gboolean x3view_key_press(GtkWidget *widget, GdkEventKey *event,
  444. gpointer data)
  445. {
  446. x3widget_view *w = (x3widget_view *)data;
  447. if (w->vc && w->vc->key)
  448. return w->vc->key(w->vc, gdk_keyval_name(event->keyval),
  449. event->state, event->keyval);
  450. x3sync();
  451. return FALSE;
  452. }
  453. x3widget *x3view(x3widget *parent, x3viewflags flags, x3viewclient *vc)
  454. {
  455. GtkWidget *container;
  456. GtkWidget *event_target;
  457. GtkWidget *drawing_area;
  458. x3widget_view *result = (x3widget_view *)malloc(sizeof(x3widget_view));
  459. GdkEventMask eventmask = 0;
  460. if (flags & x3view_scroll) {
  461. container = gtk_scrolled_window_new(NULL, NULL);
  462. drawing_area = gtk_layout_new(NULL, NULL);
  463. event_target = drawing_area;
  464. /* todo: more intelligent size requesting of view */
  465. gtk_widget_set_size_request(drawing_area, 1500, 1500);
  466. gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(container),
  467. drawing_area);
  468. } else {
  469. container = gtk_event_box_new();
  470. drawing_area = gtk_drawing_area_new();
  471. event_target = container;
  472. gtk_container_add(GTK_CONTAINER(container), drawing_area);
  473. }
  474. gtk_widget_show(container);
  475. if (flags & x3view_key) {
  476. g_object_set(GTK_OBJECT(event_target), "can-focus", TRUE, NULL);
  477. eventmask |= GDK_KEY_PRESS_MASK;
  478. g_signal_connect(G_OBJECT(event_target), "key_press_event",
  479. G_CALLBACK(x3view_key_press), result);
  480. }
  481. if (flags & x3view_click) {
  482. eventmask |= GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
  483. g_signal_connect(G_OBJECT(event_target), "button_press_event",
  484. G_CALLBACK(x3view_button_press), result);
  485. g_signal_connect(G_OBJECT(event_target), "button_release_event",
  486. G_CALLBACK(x3view_button_press), result);
  487. }
  488. if (flags & x3view_hover) {
  489. eventmask |= GDK_POINTER_MOTION_MASK;
  490. g_signal_connect(G_OBJECT(event_target), "motion_notify_event",
  491. G_CALLBACK(x3view_pointer_motion), result);
  492. }
  493. gtk_widget_add_events(event_target, eventmask);
  494. g_signal_connect(G_OBJECT(drawing_area), "expose_event",
  495. G_CALLBACK(x3view_expose), result);
  496. gtk_widget_show(drawing_area);
  497. if (flags & x3view_rgb)
  498. gtk_widget_set_double_buffered(drawing_area, FALSE);
  499. x3widget_init(&result->base, parent, NULL, container);
  500. result->flags = flags;
  501. result->vc = vc;
  502. return &result->base;
  503. }
  504. void x3view_dirty(x3widget *w)
  505. {
  506. gtk_widget_queue_draw(w->widget);
  507. }
  508. static void
  509. x3scrollto_adj(GtkAdjustment *adj, int v, int size)
  510. {
  511. if (adj && v != -1) {
  512. if (size >= adj->page_size) {
  513. /* target is bigger than adj; center as best as possible */
  514. gtk_adjustment_set_value(adj, v - 0.5 * (size - adj->page_size));
  515. } else if (adj->value > v) {
  516. gtk_adjustment_set_value(adj, v);
  517. } else if (adj->value + adj->page_size < v + size) {
  518. gtk_adjustment_set_value(adj, v + size - adj->page_size);
  519. }
  520. }
  521. }
  522. void x3view_scrollto(x3widget *w, int x, int y, int width, int height)
  523. {
  524. if (GTK_IS_SCROLLED_WINDOW(w->widget)) {
  525. GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(w->widget);
  526. x3scrollto_adj(gtk_scrolled_window_get_hadjustment(sw), x, width);
  527. x3scrollto_adj(gtk_scrolled_window_get_vadjustment(sw), y, height);
  528. }
  529. }
  530. void x3viewclient_init(x3viewclient *vc)
  531. {
  532. vc->destroy = NULL;
  533. vc->mouse = NULL;
  534. vc->key = NULL;
  535. vc->draw = NULL;
  536. }
  537. /* An argument can be made against the "fill" flag, because the same effect
  538. as turning off fill can be achieved with the align widget. */
  539. void x3setpacking(x3widget *w, int fill, int expand, int padding)
  540. {
  541. if (GTK_IS_BOX(w->widget)) {
  542. x3widget_box *wb= (x3widget_box *)w;
  543. wb->fill = fill;
  544. wb->expand = expand;
  545. wb->padding = padding;
  546. }
  547. }
  548. typedef struct {
  549. GtkWidget *parent;
  550. int resize[2];
  551. int shrink[2];
  552. int i;
  553. } x3pane_setsizing_ctx;
  554. static void
  555. x3pane_setsizing_callback(GtkWidget *child, gpointer data)
  556. {
  557. x3pane_setsizing_ctx *ctx = (x3pane_setsizing_ctx *)data;
  558. gtk_container_child_set(GTK_CONTAINER(ctx->parent),
  559. child,
  560. "resize", ctx->resize[ctx->i],
  561. "shrink", ctx->shrink[ctx->i],
  562. NULL);
  563. ctx->i++;
  564. }
  565. /* This implementation only works if the sizing is set _after_ the
  566. * children are added. It wouldn't be too hard to fix, by putting the
  567. * info in the pane's x3widget struct. */
  568. void x3pane_setsizing(x3widget *w, int child1_resize, int child1_shrink,
  569. int child2_resize, int child2_shrink)
  570. {
  571. x3pane_setsizing_ctx ctx;
  572. ctx.parent = w->widget;
  573. ctx.resize[0] = child1_resize;
  574. ctx.shrink[0] = child1_shrink;
  575. ctx.resize[1] = child2_resize;
  576. ctx.shrink[1] = child2_shrink;
  577. ctx.i = 0;
  578. if (GTK_IS_PANED(w->widget)) {
  579. gtk_container_foreach(GTK_CONTAINER(w->widget),
  580. x3pane_setsizing_callback,
  581. (gpointer)&ctx);
  582. }
  583. }
  584. void x3setactive(x3widget *w, int active)
  585. {
  586. gtk_widget_set_sensitive(w->widget, active != 0);
  587. }
  588. int x3hasfocus(x3widget *w)
  589. {
  590. GtkWidget *widget = w->widget;
  591. while (GTK_IS_CONTAINER(widget) && !GTK_IS_LAYOUT(widget))
  592. widget = x3_gtkwidget_getchild(widget);
  593. return GTK_WIDGET_HAS_FOCUS(widget);
  594. }
  595. /* 2d drawing functions, implemented using cairo */
  596. void
  597. x3moveto(x3dc *dc, double x, double y)
  598. {
  599. cairo_move_to(dc->cr, x, y);
  600. }
  601. void
  602. x3lineto(x3dc *dc, double x, double y)
  603. {
  604. cairo_line_to(dc->cr, x, y);
  605. }
  606. void
  607. x3curveto(x3dc *dc,
  608. double x1, double y1,
  609. double x2, double y2,
  610. double x3, double y3)
  611. {
  612. cairo_curve_to(dc->cr, x1, y1, x2, y2, x3, y3);
  613. }
  614. void
  615. x3closepath(x3dc *dc)
  616. {
  617. cairo_close_path(dc->cr);
  618. }
  619. void
  620. x3rectangle(x3dc *dc, double x, double y, double width, double height)
  621. {
  622. cairo_rectangle(dc->cr, x, y, width, height);
  623. }
  624. void
  625. x3getcurrentpoint(x3dc *dc, double *px, double *py)
  626. {
  627. cairo_get_current_point(dc->cr, px, py);
  628. }
  629. void
  630. x3setrgba(x3dc *dc, unsigned int rgba)
  631. {
  632. cairo_set_source_rgba(dc->cr,
  633. ((rgba >> 24) & 0xff) * (1.0/255),
  634. ((rgba >> 16) & 0xff) * (1.0/255),
  635. ((rgba >> 8) & 0xff) * (1.0/255),
  636. (rgba & 0xff) * (1.0/255));
  637. }
  638. void
  639. x3setlinewidth(x3dc *dc, double w)
  640. {
  641. cairo_set_line_width(dc->cr, w);
  642. }
  643. void
  644. x3fill(x3dc *dc)
  645. {
  646. cairo_fill(dc->cr);
  647. }
  648. void
  649. x3stroke(x3dc *dc)
  650. {
  651. cairo_stroke(dc->cr);
  652. }
  653. void
  654. x3selectfont(x3dc *dc, char *fontname, int slant, int weight)
  655. {
  656. cairo_select_font_face(dc->cr, fontname, slant, weight);
  657. }
  658. void
  659. x3setfontsize(x3dc *dc, double size)
  660. {
  661. cairo_set_font_size(dc->cr, size);
  662. }
  663. void
  664. x3showtext(x3dc *dc, char *text)
  665. {
  666. cairo_show_text(dc->cr, text);
  667. }
  668. void
  669. x3textextents(x3dc *dc, char *text, x3extents *extents)
  670. {
  671. cairo_text_extents(dc->cr, text, extents);
  672. }