1 /* -*- Mode: C; c-basic-offset: 4 -*-
2 * pygtk- Python bindings for the GTK toolkit.
3 * Copyright (C) 1998-2003 James Henstridge
4 *
5 * pygtkcellrenderer.c: stub class to help implement cell renderers.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20 * USA
21 */
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include "pygtkcellrenderer.h"
27 #include <Python.h>
28 #include "pygtk-private.h"
29
30 /* define this to print out debug messages */
31 #undef DEBUG_CELL_RENDERER
32
33 #ifndef _
34 # define _(s) (s)
35 #endif
36
37 static void pygtk_generic_cell_renderer_class_init (PyGtkGenericCellRendererClass *klass);
38 static void pygtk_generic_cell_renderer_get_size (GtkCellRenderer *cell,
39 GtkWidget *widget,
40 GdkRectangle *cell_area,
41 gint *x_offset,
42 gint *y_offset,
43 gint *width,
44 gint *height);
45 static void pygtk_generic_cell_renderer_render (GtkCellRenderer *cell,
46 GdkWindow *window,
47 GtkWidget *widget,
48 GdkRectangle *background_area,
49 GdkRectangle *cell_area,
50 GdkRectangle *expose_area,
51 GtkCellRendererState flags);
52 static gboolean pygtk_generic_cell_renderer_activate (GtkCellRenderer *cell,
53 GdkEvent *event,
54 GtkWidget *widget,
55 const gchar *path,
56 GdkRectangle *background_area,
57 GdkRectangle *cell_area,
58 GtkCellRendererState flags);
59 static GtkCellEditable *pygtk_generic_cell_renderer_start_editing (GtkCellRenderer *cell,
60 GdkEvent *event,
61 GtkWidget *widget,
62 const gchar *path,
63 GdkRectangle *background_area,
64 GdkRectangle *cell_area,
65 GtkCellRendererState flags);
66
67
68
69 GType
pygtk_generic_cell_renderer_get_type(void)70 pygtk_generic_cell_renderer_get_type(void)
71 {
72 static GType object_type = 0;
73
74 if (!object_type) {
75 static const GTypeInfo object_info = {
76 sizeof(PyGtkGenericCellRendererClass),
77 (GBaseInitFunc) NULL,
78 (GBaseFinalizeFunc) NULL,
79 (GClassInitFunc) pygtk_generic_cell_renderer_class_init,
80 NULL, /* class_finalize */
81 NULL, /* class_data */
82 sizeof(PyGtkGenericCellRenderer),
83 0, /* n_preallocs */
84 (GInstanceInitFunc) NULL,
85 };
86 object_type = g_type_register_static(GTK_TYPE_CELL_RENDERER,
87 "PyGtkGenericCellRenderer",
88 &object_info, 0);
89 }
90
91 return object_type;
92 }
93
94 static void
pygtk_generic_cell_renderer_class_init(PyGtkGenericCellRendererClass * klass)95 pygtk_generic_cell_renderer_class_init(PyGtkGenericCellRendererClass *klass)
96 {
97 GtkCellRendererClass *cell_renderer_class = (GtkCellRendererClass*) klass;
98 cell_renderer_class->get_size = pygtk_generic_cell_renderer_get_size;
99 cell_renderer_class->render = pygtk_generic_cell_renderer_render;
100 cell_renderer_class->activate = pygtk_generic_cell_renderer_activate;
101 cell_renderer_class->start_editing = pygtk_generic_cell_renderer_start_editing;
102 }
103
104 #define METHOD_PREFIX "on_"
105
106 static void
pygtk_generic_cell_renderer_get_size(GtkCellRenderer * cell,GtkWidget * widget,GdkRectangle * cell_area,gint * x_offset,gint * y_offset,gint * width,gint * height)107 pygtk_generic_cell_renderer_get_size (GtkCellRenderer *cell,
108 GtkWidget *widget,
109 GdkRectangle *cell_area,
110 gint *x_offset,
111 gint *y_offset,
112 gint *width,
113 gint *height)
114 {
115 PyGILState_STATE state;
116 PyObject *self, *py_ret, *py_widget, *py_cell_area;
117 gint my_x, my_y, my_width, my_height;
118
119 g_return_if_fail(PYGTK_IS_GENERIC_CELL_RENDERER (cell));
120
121 state = pyg_gil_state_ensure();
122
123 self = pygobject_new((GObject *)cell);
124
125 #ifdef DEBUG_CELL_RENDERER
126 g_message ("get_size()");
127 #endif
128 py_widget = pygobject_new((GObject *)widget);
129 py_cell_area = pyg_boxed_new(GDK_TYPE_RECTANGLE, cell_area, TRUE, TRUE);
130
131 py_ret = PyObject_CallMethod(self, METHOD_PREFIX "get_size", "OO",
132 py_widget, py_cell_area);
133 if (!py_ret) {
134 PyErr_Print();
135 Py_DECREF(py_widget);
136 Py_DECREF(py_cell_area);
137 pyg_gil_state_release(state);
138 return;
139 }
140 Py_DECREF(py_widget);
141 Py_DECREF(py_cell_area);
142
143 if (!PyArg_ParseTuple(py_ret, "iiii",
144 &my_x, &my_y, &my_width, &my_height)) {
145 PyErr_Clear();
146 Py_DECREF(py_ret);
147 pyg_gil_state_release(state);
148 g_warning("could not parse return value of get_size() method. "
149 "Should be of form (x_offset, y_offset, width, height)");
150 return;
151 }
152
153 pyg_gil_state_release(state);
154
155 /* success */
156 if (x_offset)
157 *x_offset = my_x;
158
159 if (y_offset)
160 *y_offset = my_y;
161
162 if (width)
163 *width = my_width;
164
165 if (height)
166 *height = my_height;
167
168 }
169
170 static void
pygtk_generic_cell_renderer_render(GtkCellRenderer * cell,GdkWindow * window,GtkWidget * widget,GdkRectangle * background_area,GdkRectangle * cell_area,GdkRectangle * expose_area,GtkCellRendererState flags)171 pygtk_generic_cell_renderer_render (GtkCellRenderer *cell,
172 GdkWindow *window,
173 GtkWidget *widget,
174 GdkRectangle *background_area,
175 GdkRectangle *cell_area,
176 GdkRectangle *expose_area,
177 GtkCellRendererState flags)
178 {
179 PyGILState_STATE state;
180 PyObject *self, *py_ret, *py_window, *py_widget;
181 PyObject *py_background_area, *py_cell_area, *py_expose_area;
182
183 g_return_if_fail(PYGTK_IS_GENERIC_CELL_RENDERER (cell));
184
185 state = pyg_gil_state_ensure();
186
187 self = pygobject_new((GObject *)cell);
188
189 #ifdef DEBUG_CELL_RENDERER
190 g_message ("render()");
191 #endif
192 py_window = pygobject_new((GObject *)window);
193 py_widget = pygobject_new((GObject *)widget);
194 py_background_area = pyg_boxed_new(GDK_TYPE_RECTANGLE, background_area, TRUE, TRUE);
195 py_cell_area = pyg_boxed_new(GDK_TYPE_RECTANGLE, cell_area, TRUE, TRUE);
196 py_expose_area = pyg_boxed_new(GDK_TYPE_RECTANGLE, expose_area, TRUE, TRUE);
197 py_ret = PyObject_CallMethod(self, METHOD_PREFIX "render", "OOOOOi",
198 py_window, py_widget, py_background_area,
199 py_cell_area, py_expose_area, flags);
200 if (!py_ret) {
201 PyErr_Print();
202 }
203
204 Py_DECREF(py_window);
205 Py_DECREF(py_widget);
206 Py_DECREF(py_background_area);
207 Py_DECREF(py_cell_area);
208 Py_DECREF(py_expose_area);
209
210 pyg_gil_state_release(state);
211 }
212
213 static gboolean
pygtk_generic_cell_renderer_activate(GtkCellRenderer * cell,GdkEvent * event,GtkWidget * widget,const gchar * path,GdkRectangle * background_area,GdkRectangle * cell_area,GtkCellRendererState flags)214 pygtk_generic_cell_renderer_activate (GtkCellRenderer *cell,
215 GdkEvent *event,
216 GtkWidget *widget,
217 const gchar *path,
218 GdkRectangle *background_area,
219 GdkRectangle *cell_area,
220 GtkCellRendererState flags)
221 {
222 PyGILState_STATE state;
223 PyObject *self, *py_ret, *py_event, *py_widget;
224 PyObject *py_background_area, *py_cell_area;
225 gboolean ret = FALSE;
226
227 g_return_val_if_fail(PYGTK_IS_GENERIC_CELL_RENDERER (cell), FALSE);
228
229 state = pyg_gil_state_ensure();
230
231 self = pygobject_new((GObject *)cell);
232
233 #ifdef DEBUG_CELL_RENDERER
234 g_message ("activate()");
235 #endif
236 py_event = pyg_boxed_new(GDK_TYPE_EVENT, event, FALSE, FALSE);
237 py_widget = pygobject_new((GObject *)widget);
238 py_background_area = pyg_boxed_new(GDK_TYPE_RECTANGLE, background_area, TRUE, TRUE);
239 py_cell_area = pyg_boxed_new(GDK_TYPE_RECTANGLE, cell_area, TRUE, TRUE);
240
241 py_ret = PyObject_CallMethod(self, METHOD_PREFIX "activate", "OOzOOi",
242 py_event, py_widget, path, py_background_area,
243 py_cell_area, flags);
244 if (!py_ret) {
245 PyErr_Print();
246 goto out;
247 }
248
249 ret = PyObject_IsTrue(py_ret);
250 Py_DECREF(py_ret);
251
252 out:
253 pygtk_boxed_unref_shared(py_event);
254 Py_DECREF(py_widget);
255 Py_DECREF(py_background_area);
256 Py_DECREF(py_cell_area);
257 pyg_gil_state_release(state);
258 return ret;
259 }
260
261 static GtkCellEditable *
pygtk_generic_cell_renderer_start_editing(GtkCellRenderer * cell,GdkEvent * event,GtkWidget * widget,const gchar * path,GdkRectangle * background_area,GdkRectangle * cell_area,GtkCellRendererState flags)262 pygtk_generic_cell_renderer_start_editing (GtkCellRenderer *cell,
263 GdkEvent *event,
264 GtkWidget *widget,
265 const gchar *path,
266 GdkRectangle *background_area,
267 GdkRectangle *cell_area,
268 GtkCellRendererState flags)
269 {
270 PyGILState_STATE state;
271 PyObject *self, *py_ret, *py_event, *py_widget;
272 PyObject *py_background_area, *py_cell_area;
273 GtkCellEditable *ret = NULL;
274 extern PyTypeObject PyGtkCellEditable_Type;
275
276 g_return_val_if_fail(PYGTK_IS_GENERIC_CELL_RENDERER (cell), NULL);
277
278 state = pyg_gil_state_ensure();
279
280 self = pygobject_new((GObject *)cell);
281
282 #ifdef DEBUG_CELL_RENDERER
283 g_message ("start_editing()");
284 #endif
285 py_event = pyg_boxed_new(GDK_TYPE_EVENT, event, FALSE, FALSE);
286 py_widget = pygobject_new((GObject *)widget);
287 py_background_area = pyg_boxed_new(GDK_TYPE_RECTANGLE, background_area, TRUE, TRUE);
288 py_cell_area = pyg_boxed_new(GDK_TYPE_RECTANGLE, cell_area, TRUE, TRUE);
289
290 py_ret = PyObject_CallMethod(self, METHOD_PREFIX "start_editing", "OOzOOi",
291 py_event, py_widget, path, py_background_area,
292 py_cell_area, flags);
293 if (!py_ret) {
294 PyErr_Print();
295 Py_DECREF(py_event);
296 Py_DECREF(py_widget);
297 Py_DECREF(py_background_area);
298 Py_DECREF(py_cell_area);
299 pyg_gil_state_release(state);
300 return NULL;
301 }
302 Py_DECREF(py_event);
303 Py_DECREF(py_widget);
304 Py_DECREF(py_background_area);
305 Py_DECREF(py_cell_area);
306 if (py_ret == Py_None) {
307 ret = NULL;
308 }
309 else if (pygobject_check(py_ret, &PyGtkCellEditable_Type)) {
310 ret = GTK_CELL_EDITABLE(g_object_ref(pygobject_get(py_ret)));
311 }
312 else {
313 g_warning("return of start_editing() was not a GtkCellEditable");
314 }
315 Py_DECREF(py_ret);
316 pyg_gil_state_release(state);
317 return ret;
318 }
319
320 GtkCellRenderer *
pygtk_generic_cell_renderer_new(void)321 pygtk_generic_cell_renderer_new(void)
322 {
323 if (PyErr_Warn(PyExc_DeprecationWarning,
324 "subclass gtk.CellRenderer and override do_xxx methods") < 0)
325 return NULL;
326 return GTK_CELL_RENDERER(
327 g_object_new(PYGTK_TYPE_GENERIC_CELL_RENDERER, NULL));
328 }
329