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