summaryrefslogtreecommitdiff
path: root/new/newcontrol_unix.c
blob: 870406c9a7b5403bb11deb06cc9dc55bbd7b7658 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 7 april 2015
#include "uipriv_unix.h"

typedef struct uiSingleWidgetControl uiSingleWidgetControl;

struct uiSingleWidgetControl {
	uiControl control;
	GtkWidget *widget;
	GtkWidget *scrolledWindow;
	GtkWidget *immediate;		// the widget that is added to the parent container; either widget or scrolledWindow
	void *data;
	uintptr_t parent;
};

#define S(c) ((uiSingleWidgetControl *) (c))

static void singleDestroy(uiControl *c)
{
	gtk_widget_destroy(S(c)->immediate);
}

static uintptr_t singleHandle(uiControl *c)
{
	return (uintptr_t) (S(c)->widget);
}

static void singleSetParent(uiControl *c, uintptr_t parent)
{
	uiSingleWidgetControl *s = S(c);

	s->parent = parent;
	gtk_container_add(GTK_CONTAINER(s->parent), s->immediate);
	updateParent(s->parent);
}

static void singleRemoveParent(uiControl *c)
{
	uiSingleWidgetControl *s = S(c);
	uintptr_t oldparent;

	oldparent = s->parent;
	s->parent = 0;
	gtk_container_remove(GTK_CONTAINER(oldparent), s->immediate);
	updateParent(oldparent);
}

static uiSize singlePreferredSize(uiControl *c, uiSizing *d)
{
	uiSize size;
	GtkRequisition natural;

	// use the natural size as the minimum size is an *absolute* minimum
	// for example, if a label has ellipsizing on, it can be the width of the ellipses, not the text
	// there is a warning about height-for-width sizing, but in my tests this isn't an issue
	gtk_widget_get_preferred_size(S(c)->widget, NULL, &natural);
	size.width = natural.width;
	size.height = natural.height;
	return size;
}

static void singleResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d)
{
	GtkAllocation a;

	a.x = x;
	a.y = y;
	a.width = width;
	a.height = height;
	gtk_widget_size_allocate(S(c)->immediate, &a);
}

static void onDestroy(GtkWidget *widget, gpointer data)
{
	uiSingleWidgetControl *c = (uiSingleWidgetControl *) data;

	uiFree(c);
}

uiControl *uiUnixNewControl(GType type, gboolean inScrolledWindow, gboolean scrolledWindowHasBorder, void *data, const char *firstProperty, ...)
{
	uiSingleWidgetControl *c;
	va_list ap;

	c = uiNew(uiSingleWidgetControl);

	va_start(ap, firstProperty);
	c->widget = GTK_WIDGET(g_object_new_valist(type, firstProperty, ap));
	va_end(ap);
	c->immediate = c->widget;

	if (inScrolledWindow) {
		c->scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
		if (!GTK_IS_SCROLLABLE(c->widget))
			gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(c->scrolledWindow), c->widget);
		else
			gtk_container_add(GTK_CONTAINER(c->scrolledWindow), c->widget);
		if (scrolledWindowHasBorder)
			gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(c->scrolledWindow), GTK_SHADOW_IN);
		c->immediate = c->scrolledWindow;
	}

	// we need to keep an extra reference on the immediate widget
	// this is so uiControlDestroy() can work regardless of when it is called and who calls it
	// without this:
	// - end user call works (only one ref)
	// - call in uiContainer destructor fails (uiContainer ref freed)
	// with this:
	// - end user call works (shoudn't be in any container)
	// - call in uiContainer works (both refs freed)
	// this also ensures singleRemoveParent() works properly
	g_object_ref_sink(c->immediate);
	// and let's free the uiSingleWidgetControl with it
	g_signal_connect(c->immediate, "destroy", G_CALLBACK(onDestroy), c);

	c->control.destroy = singleDestroy;
	c->control.handle = singleHandle;
	c->control.setParent = singleSetParent;
	c->control.removeParent = singleRemoveParent;
	c->control.preferredSize = singlePreferredSize;
	c->control.resize = singleResize;

	c->data = data;

	return (uiControl *) c;
}

void *uiUnixControlData(uiControl *c)
{
	return S(c)->data;
}