1 /* GTK - The GIMP Toolkit
2 * Copyright © 2013 Carlos Garnacho <carlosg@gnome.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19 #include "gtk/gtk.h"
20 #include "gtkmagnifierprivate.h"
21 #include "gtkintl.h"
22
23 enum {
24 PROP_INSPECTED = 1,
25 PROP_RESIZE,
26 PROP_MAGNIFICATION
27 };
28
29 typedef struct _GtkMagnifierPrivate GtkMagnifierPrivate;
30
31 struct _GtkMagnifierPrivate
32 {
33 GtkWidget *inspected;
34 gdouble magnification;
35 gint x;
36 gint y;
37 gboolean resize;
38 gulong draw_handler;
39 gulong resize_handler;
40 };
41
G_DEFINE_TYPE_WITH_PRIVATE(GtkMagnifier,_gtk_magnifier,GTK_TYPE_WIDGET)42 G_DEFINE_TYPE_WITH_PRIVATE (GtkMagnifier, _gtk_magnifier,
43 GTK_TYPE_WIDGET)
44
45 static void
46 _gtk_magnifier_set_property (GObject *object,
47 guint param_id,
48 const GValue *value,
49 GParamSpec *pspec)
50 {
51 switch (param_id)
52 {
53 case PROP_INSPECTED:
54 _gtk_magnifier_set_inspected (GTK_MAGNIFIER (object),
55 g_value_get_object (value));
56 break;
57 case PROP_MAGNIFICATION:
58 _gtk_magnifier_set_magnification (GTK_MAGNIFIER (object),
59 g_value_get_double (value));
60 break;
61 case PROP_RESIZE:
62 _gtk_magnifier_set_resize (GTK_MAGNIFIER (object),
63 g_value_get_boolean (value));
64 break;
65 default:
66 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
67 }
68 }
69
70 static void
_gtk_magnifier_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)71 _gtk_magnifier_get_property (GObject *object,
72 guint param_id,
73 GValue *value,
74 GParamSpec *pspec)
75 {
76 GtkMagnifier *magnifier;
77 GtkMagnifierPrivate *priv;
78
79 magnifier = GTK_MAGNIFIER (object);
80 priv = _gtk_magnifier_get_instance_private (magnifier);
81
82 switch (param_id)
83 {
84 case PROP_INSPECTED:
85 g_value_set_object (value, priv->inspected);
86 break;
87 case PROP_MAGNIFICATION:
88 g_value_set_double (value, priv->magnification);
89 break;
90 case PROP_RESIZE:
91 g_value_set_boolean (value, priv->resize);
92 break;
93 default:
94 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
95 }
96 }
97
98 static gboolean
_gtk_magnifier_draw(GtkWidget * widget,cairo_t * cr)99 _gtk_magnifier_draw (GtkWidget *widget,
100 cairo_t *cr)
101 {
102 GtkAllocation allocation, inspected_alloc;
103 GtkMagnifier *magnifier;
104 GtkMagnifierPrivate *priv;
105 gdouble x, y;
106
107 magnifier = GTK_MAGNIFIER (widget);
108 priv = _gtk_magnifier_get_instance_private (magnifier);
109
110 if (priv->inspected == NULL)
111 return FALSE;
112
113 if (!gtk_widget_is_visible (priv->inspected))
114 return FALSE;
115
116 gtk_widget_get_allocation (widget, &allocation);
117 gtk_widget_get_allocation (priv->inspected, &inspected_alloc);
118
119 if (!priv->resize)
120 cairo_translate (cr, allocation.width / 2, allocation.height / 2);
121
122 x = CLAMP (priv->x, 0, inspected_alloc.width);
123 y = CLAMP (priv->y, 0, inspected_alloc.height);
124
125 cairo_save (cr);
126 cairo_scale (cr, priv->magnification, priv->magnification);
127 cairo_translate (cr, -x, -y);
128 g_signal_handler_block (priv->inspected, priv->draw_handler);
129 gtk_widget_draw (priv->inspected, cr);
130 g_signal_handler_unblock (priv->inspected, priv->draw_handler);
131 cairo_restore (cr);
132
133 return TRUE;
134 }
135
136 static void
gtk_magnifier_get_preferred_width(GtkWidget * widget,gint * minimum_width,gint * natural_width)137 gtk_magnifier_get_preferred_width (GtkWidget *widget,
138 gint *minimum_width,
139 gint *natural_width)
140 {
141 GtkMagnifier *magnifier;
142 GtkMagnifierPrivate *priv;
143 gint width;
144
145 magnifier = GTK_MAGNIFIER (widget);
146 priv = _gtk_magnifier_get_instance_private (magnifier);
147
148 if (priv->resize && priv->inspected)
149 width = priv->magnification * gtk_widget_get_allocated_width (priv->inspected);
150 else
151 width = 0;
152
153 *minimum_width = width;
154 *natural_width = width;
155 }
156
157 static void
gtk_magnifier_get_preferred_height(GtkWidget * widget,gint * minimum_height,gint * natural_height)158 gtk_magnifier_get_preferred_height (GtkWidget *widget,
159 gint *minimum_height,
160 gint *natural_height)
161 {
162 GtkMagnifier *magnifier;
163 GtkMagnifierPrivate *priv;
164 gint height;
165
166 magnifier = GTK_MAGNIFIER (widget);
167 priv = _gtk_magnifier_get_instance_private (magnifier);
168
169 if (priv->resize && priv->inspected)
170 height = priv->magnification * gtk_widget_get_allocated_height (priv->inspected);
171 else
172 height = 0;
173
174 *minimum_height = height;
175 *natural_height = height;
176 }
177
178 static void
resize_handler(GtkWidget * widget,GtkAllocation * alloc,GtkWidget * magnifier)179 resize_handler (GtkWidget *widget,
180 GtkAllocation *alloc,
181 GtkWidget *magnifier)
182 {
183 gtk_widget_queue_resize (magnifier);
184 }
185
186 static void
connect_resize_handler(GtkMagnifier * magnifier)187 connect_resize_handler (GtkMagnifier *magnifier)
188 {
189 GtkMagnifierPrivate *priv;
190
191 priv = _gtk_magnifier_get_instance_private (magnifier);
192
193 if (priv->inspected && priv->resize)
194 priv->resize_handler = g_signal_connect (priv->inspected, "size-allocate",
195 G_CALLBACK (resize_handler), magnifier);
196 }
197
198 static void
disconnect_resize_handler(GtkMagnifier * magnifier)199 disconnect_resize_handler (GtkMagnifier *magnifier)
200 {
201 GtkMagnifierPrivate *priv;
202
203 priv = _gtk_magnifier_get_instance_private (magnifier);
204
205 if (priv->resize_handler)
206 {
207 if (priv->inspected)
208 g_signal_handler_disconnect (priv->inspected, priv->resize_handler);
209 priv->resize_handler = 0;
210 }
211 }
212
213 static gboolean
draw_handler(GtkWidget * widget,cairo_t * cr,GtkWidget * magnifier)214 draw_handler (GtkWidget *widget,
215 cairo_t *cr,
216 GtkWidget *magnifier)
217 {
218 gtk_widget_queue_draw (magnifier);
219 return FALSE;
220 }
221
222 static void
connect_draw_handler(GtkMagnifier * magnifier)223 connect_draw_handler (GtkMagnifier *magnifier)
224 {
225 GtkMagnifierPrivate *priv;
226
227 priv = _gtk_magnifier_get_instance_private (magnifier);
228
229 if (!priv->draw_handler)
230 {
231 if (priv->inspected)
232 priv->draw_handler = g_signal_connect (priv->inspected, "draw",
233 G_CALLBACK (draw_handler), magnifier);
234 }
235 }
236
237 static void
disconnect_draw_handler(GtkMagnifier * magnifier)238 disconnect_draw_handler (GtkMagnifier *magnifier)
239 {
240 GtkMagnifierPrivate *priv;
241
242 priv = _gtk_magnifier_get_instance_private (magnifier);
243
244 if (priv->draw_handler)
245 {
246 if (priv->inspected)
247 g_signal_handler_disconnect (priv->inspected, priv->draw_handler);
248 priv->draw_handler = 0;
249 }
250 }
251
252 static void
_gtk_magnifier_destroy(GtkWidget * widget)253 _gtk_magnifier_destroy (GtkWidget *widget)
254 {
255 _gtk_magnifier_set_inspected (GTK_MAGNIFIER (widget), NULL);
256
257 GTK_WIDGET_CLASS (_gtk_magnifier_parent_class)->destroy (widget);
258 }
259
260 static void
gtk_magnifier_map(GtkWidget * widget)261 gtk_magnifier_map (GtkWidget *widget)
262 {
263 connect_draw_handler (GTK_MAGNIFIER (widget));
264
265 GTK_WIDGET_CLASS (_gtk_magnifier_parent_class)->map (widget);
266 }
267
268 static void
gtk_magnifier_unmap(GtkWidget * widget)269 gtk_magnifier_unmap (GtkWidget *widget)
270 {
271 GTK_WIDGET_CLASS (_gtk_magnifier_parent_class)->unmap (widget);
272
273 disconnect_draw_handler (GTK_MAGNIFIER (widget));
274 }
275
276 static void
_gtk_magnifier_class_init(GtkMagnifierClass * klass)277 _gtk_magnifier_class_init (GtkMagnifierClass *klass)
278 {
279 GObjectClass *object_class = G_OBJECT_CLASS (klass);
280 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
281
282 object_class->set_property = _gtk_magnifier_set_property;
283 object_class->get_property = _gtk_magnifier_get_property;
284
285 widget_class->destroy = _gtk_magnifier_destroy;
286 widget_class->draw = _gtk_magnifier_draw;
287 widget_class->get_preferred_width = gtk_magnifier_get_preferred_width;
288 widget_class->get_preferred_height = gtk_magnifier_get_preferred_height;
289 widget_class->map = gtk_magnifier_map;
290 widget_class->unmap = gtk_magnifier_unmap;
291
292 g_object_class_install_property (object_class,
293 PROP_INSPECTED,
294 g_param_spec_object ("inspected",
295 P_("Inspected"),
296 P_("Inspected widget"),
297 GTK_TYPE_WIDGET,
298 G_PARAM_READWRITE));
299 g_object_class_install_property (object_class,
300 PROP_MAGNIFICATION,
301 g_param_spec_double ("magnification",
302 P_("magnification"),
303 P_("magnification"),
304 1, G_MAXDOUBLE, 1,
305 G_PARAM_READWRITE));
306 g_object_class_install_property (object_class,
307 PROP_RESIZE,
308 g_param_spec_boolean ("resize",
309 P_("resize"),
310 P_("resize"),
311 FALSE,
312 G_PARAM_READWRITE));
313 }
314
315 static void
_gtk_magnifier_init(GtkMagnifier * magnifier)316 _gtk_magnifier_init (GtkMagnifier *magnifier)
317 {
318 GtkWidget *widget = GTK_WIDGET (magnifier);
319 GtkMagnifierPrivate *priv;
320
321 priv = _gtk_magnifier_get_instance_private (magnifier);
322
323 gtk_widget_set_events (widget,
324 gtk_widget_get_events (widget));
325
326 gtk_widget_set_has_window (widget, FALSE);
327 priv->magnification = 1;
328 priv->resize = FALSE;
329 }
330
331 GtkWidget *
_gtk_magnifier_new(GtkWidget * inspected)332 _gtk_magnifier_new (GtkWidget *inspected)
333 {
334 g_return_val_if_fail (GTK_IS_WIDGET (inspected), NULL);
335
336 return g_object_new (GTK_TYPE_MAGNIFIER,
337 "inspected", inspected,
338 NULL);
339 }
340
341 GtkWidget *
_gtk_magnifier_get_inspected(GtkMagnifier * magnifier)342 _gtk_magnifier_get_inspected (GtkMagnifier *magnifier)
343 {
344 GtkMagnifierPrivate *priv;
345
346 g_return_val_if_fail (GTK_IS_MAGNIFIER (magnifier), NULL);
347
348 priv = _gtk_magnifier_get_instance_private (magnifier);
349
350 return priv->inspected;
351 }
352
353 void
_gtk_magnifier_set_inspected(GtkMagnifier * magnifier,GtkWidget * inspected)354 _gtk_magnifier_set_inspected (GtkMagnifier *magnifier,
355 GtkWidget *inspected)
356 {
357 GtkMagnifierPrivate *priv;
358
359 g_return_if_fail (GTK_IS_MAGNIFIER (magnifier));
360
361 priv = _gtk_magnifier_get_instance_private (magnifier);
362
363 if (priv->inspected == inspected)
364 return;
365
366 disconnect_draw_handler (magnifier);
367 disconnect_resize_handler (magnifier);
368
369 if (priv->inspected)
370 g_object_remove_weak_pointer (G_OBJECT (priv->inspected),
371 (gpointer *) &priv->inspected);
372 priv->inspected = inspected;
373 if (priv->inspected)
374 g_object_add_weak_pointer (G_OBJECT (priv->inspected),
375 (gpointer *) &priv->inspected);
376
377 if (gtk_widget_get_mapped (GTK_WIDGET (magnifier)))
378 connect_draw_handler (magnifier);
379 connect_resize_handler (magnifier);
380
381 g_object_notify (G_OBJECT (magnifier), "inspected");
382 }
383
384 void
_gtk_magnifier_set_coords(GtkMagnifier * magnifier,gdouble x,gdouble y)385 _gtk_magnifier_set_coords (GtkMagnifier *magnifier,
386 gdouble x,
387 gdouble y)
388 {
389 GtkMagnifierPrivate *priv;
390
391 g_return_if_fail (GTK_IS_MAGNIFIER (magnifier));
392
393 priv = _gtk_magnifier_get_instance_private (magnifier);
394
395 if (priv->x == x && priv->y == y)
396 return;
397
398 priv->x = x;
399 priv->y = y;
400
401 if (gtk_widget_is_visible (GTK_WIDGET (magnifier)))
402 gtk_widget_queue_draw (GTK_WIDGET (magnifier));
403 }
404
405 void
_gtk_magnifier_get_coords(GtkMagnifier * magnifier,gdouble * x,gdouble * y)406 _gtk_magnifier_get_coords (GtkMagnifier *magnifier,
407 gdouble *x,
408 gdouble *y)
409 {
410 GtkMagnifierPrivate *priv;
411
412 g_return_if_fail (GTK_IS_MAGNIFIER (magnifier));
413
414 priv = _gtk_magnifier_get_instance_private (magnifier);
415
416 if (x)
417 *x = priv->x;
418
419 if (y)
420 *y = priv->y;
421 }
422
423 void
_gtk_magnifier_set_magnification(GtkMagnifier * magnifier,gdouble magnification)424 _gtk_magnifier_set_magnification (GtkMagnifier *magnifier,
425 gdouble magnification)
426 {
427 GtkMagnifierPrivate *priv;
428
429 g_return_if_fail (GTK_IS_MAGNIFIER (magnifier));
430
431 priv = _gtk_magnifier_get_instance_private (magnifier);
432
433 if (priv->magnification == magnification)
434 return;
435
436 priv->magnification = magnification;
437 g_object_notify (G_OBJECT (magnifier), "magnification");
438
439 if (priv->resize)
440 gtk_widget_queue_resize (GTK_WIDGET (magnifier));
441
442 if (gtk_widget_is_visible (GTK_WIDGET (magnifier)))
443 gtk_widget_queue_draw (GTK_WIDGET (magnifier));
444 }
445
446 gdouble
_gtk_magnifier_get_magnification(GtkMagnifier * magnifier)447 _gtk_magnifier_get_magnification (GtkMagnifier *magnifier)
448 {
449 GtkMagnifierPrivate *priv;
450
451 g_return_val_if_fail (GTK_IS_MAGNIFIER (magnifier), 1);
452
453 priv = _gtk_magnifier_get_instance_private (magnifier);
454
455 return priv->magnification;
456 }
457
458 void
_gtk_magnifier_set_resize(GtkMagnifier * magnifier,gboolean resize)459 _gtk_magnifier_set_resize (GtkMagnifier *magnifier,
460 gboolean resize)
461 {
462 GtkMagnifierPrivate *priv;
463
464 g_return_if_fail (GTK_IS_MAGNIFIER (magnifier));
465
466 priv = _gtk_magnifier_get_instance_private (magnifier);
467
468 if (priv->resize == resize)
469 return;
470
471 priv->resize = resize;
472
473 gtk_widget_queue_resize (GTK_WIDGET (magnifier));
474 if (resize)
475 connect_resize_handler (magnifier);
476 else
477 disconnect_resize_handler (magnifier);
478 }
479
480 gboolean
_gtk_magnifier_get_resize(GtkMagnifier * magnifier)481 _gtk_magnifier_get_resize (GtkMagnifier *magnifier)
482 {
483 GtkMagnifierPrivate *priv;
484
485 g_return_val_if_fail (GTK_IS_MAGNIFIER (magnifier), FALSE);
486
487 priv = _gtk_magnifier_get_instance_private (magnifier);
488
489 return priv->resize;
490 }
491