[19538] | 1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
---|
| 2 | /* This file is part of the GtkHTML library. |
---|
| 3 | |
---|
| 4 | Copyright (C) 1997 Martin Jones (mjones@kde.org) |
---|
| 5 | Copyright (C) 1997 Torben Weis (weis@kde.org) |
---|
| 6 | Copyright (C) 1999 Helix Code, Inc. |
---|
| 7 | |
---|
| 8 | This library is free software; you can redistribute it and/or |
---|
| 9 | modify it under the terms of the GNU Library General Public |
---|
| 10 | License as published by the Free Software Foundation; either |
---|
| 11 | version 2 of the License, or (at your option) any later version. |
---|
| 12 | |
---|
| 13 | This library is distributed in the hope that it will be useful, |
---|
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
| 16 | Library General Public License for more details. |
---|
| 17 | |
---|
| 18 | You should have received a copy of the GNU Library General Public License |
---|
| 19 | along with this library; see the file COPYING.LIB. If not, write to |
---|
| 20 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
| 21 | Boston, MA 02111-1307, USA. |
---|
| 22 | */ |
---|
| 23 | |
---|
| 24 | #include <config.h> |
---|
| 25 | #include <string.h> |
---|
| 26 | #include <stdio.h> |
---|
| 27 | #include <gtk/gtksignal.h> |
---|
| 28 | #include "gtkhtml.h" |
---|
| 29 | #include "gtkhtml-embedded.h" |
---|
| 30 | #include "htmlembedded.h" |
---|
| 31 | #include "htmlframe.h" |
---|
| 32 | #include "htmliframe.h" |
---|
| 33 | #include "htmlpainter.h" |
---|
| 34 | #include "htmlengine.h" |
---|
| 35 | |
---|
| 36 | HTMLEmbeddedClass html_embedded_class; |
---|
| 37 | static HTMLObjectClass *parent_class = NULL; |
---|
| 38 | |
---|
[21115] | 39 | #define d(x) |
---|
| 40 | |
---|
[19538] | 41 | static void |
---|
| 42 | copy (HTMLObject *self, |
---|
| 43 | HTMLObject *dest) |
---|
| 44 | { |
---|
| 45 | (* HTML_OBJECT_CLASS (parent_class)->copy) (self, dest); |
---|
| 46 | |
---|
| 47 | /* FIXME g_warning ("HTMLEmbedded::copy is not complete."); */ |
---|
| 48 | |
---|
| 49 | HTML_EMBEDDED (dest)->name = g_strdup (HTML_EMBEDDED (self)->name); |
---|
| 50 | HTML_EMBEDDED (dest)->value = g_strdup (HTML_EMBEDDED (self)->value); |
---|
| 51 | HTML_EMBEDDED (dest)->form = HTML_EMBEDDED (self)->form; |
---|
| 52 | |
---|
| 53 | HTML_EMBEDDED (dest)->widget = NULL; |
---|
| 54 | HTML_EMBEDDED (dest)->parent = NULL; |
---|
| 55 | |
---|
| 56 | HTML_EMBEDDED (dest)->abs_x = HTML_EMBEDDED (self)->abs_x; |
---|
| 57 | HTML_EMBEDDED (dest)->abs_y = HTML_EMBEDDED (self)->abs_y; |
---|
| 58 | } |
---|
| 59 | |
---|
| 60 | static void |
---|
| 61 | draw (HTMLObject *o, |
---|
| 62 | HTMLPainter *p, |
---|
| 63 | gint x, gint y, |
---|
| 64 | gint width, gint height, |
---|
| 65 | gint tx, gint ty) |
---|
| 66 | { |
---|
| 67 | HTMLEmbedded *element = HTML_EMBEDDED(o); |
---|
| 68 | gint new_x, new_y; |
---|
| 69 | |
---|
[21115] | 70 | d (printf ("draw embedded %p\n", element)); |
---|
[19538] | 71 | if (!element->widget) |
---|
| 72 | return; |
---|
| 73 | |
---|
| 74 | if (element->parent) { |
---|
| 75 | new_x = o->x + tx; |
---|
| 76 | new_y = o->y + ty - o->ascent; |
---|
| 77 | |
---|
| 78 | if (element->widget->parent) { |
---|
[21115] | 79 | if (new_x != element->abs_x || new_y != element->abs_y) { |
---|
| 80 | d (printf ("element: %p moveto: %d,%d shown: %d\n", element, new_x, new_y, GTK_WIDGET_VISIBLE (element->widget))); |
---|
[19538] | 81 | gtk_layout_move (GTK_LAYOUT(element->parent), element->widget, new_x, new_y); |
---|
[21115] | 82 | } else if (!GTK_HTML (element->parent)->engine->expose) |
---|
[19538] | 83 | gtk_widget_queue_draw (element->widget); |
---|
| 84 | } |
---|
| 85 | |
---|
| 86 | element->abs_x = new_x; |
---|
| 87 | element->abs_y = new_y; |
---|
| 88 | |
---|
[21115] | 89 | if (!element->widget->parent) { |
---|
| 90 | d (printf ("element: %p put: %d,%d shown: %d\n", element, new_x, new_y, GTK_WIDGET_VISIBLE (element->widget))); |
---|
[19538] | 91 | gtk_layout_put (GTK_LAYOUT(element->parent), element->widget, new_x, new_y); |
---|
[21115] | 92 | } |
---|
[19538] | 93 | } |
---|
| 94 | |
---|
[21115] | 95 | d (printf ("draw embedded %p - call painter\n", element)); |
---|
[19538] | 96 | html_painter_draw_embedded (p, element, tx, ty); |
---|
| 97 | } |
---|
| 98 | |
---|
| 99 | static void |
---|
| 100 | destroy (HTMLObject *o) |
---|
| 101 | { |
---|
| 102 | HTMLEmbedded *element; |
---|
| 103 | |
---|
[21115] | 104 | d (printf ("destroy embedded %p\n", o)); |
---|
[19538] | 105 | element = HTML_EMBEDDED (o); |
---|
| 106 | |
---|
| 107 | if(element->name) |
---|
| 108 | g_free(element->name); |
---|
| 109 | if(element->value) |
---|
| 110 | g_free(element->value); |
---|
| 111 | if(element->widget) { |
---|
| 112 | gtk_widget_hide (element->widget); |
---|
| 113 | g_signal_handlers_disconnect_matched (element->widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, element); |
---|
| 114 | if (element->changed_id > 0) |
---|
| 115 | g_signal_handler_disconnect (element->widget, element->changed_id); |
---|
| 116 | g_object_set_data (G_OBJECT (element->widget), "embeddedelement", NULL); |
---|
| 117 | if (element->widget->parent && element->parent) { |
---|
| 118 | g_assert (element->widget->parent == element->parent); |
---|
| 119 | gtk_container_remove (GTK_CONTAINER (element->parent), element->widget); |
---|
| 120 | } else { |
---|
| 121 | gtk_object_sink (GTK_OBJECT (element->widget)); |
---|
| 122 | } |
---|
| 123 | } |
---|
| 124 | |
---|
| 125 | HTML_OBJECT_CLASS (parent_class)->destroy (o); |
---|
| 126 | } |
---|
| 127 | |
---|
| 128 | static void |
---|
| 129 | reset (HTMLEmbedded *e) |
---|
| 130 | { |
---|
| 131 | /* Nothing to do? */ |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | static gint |
---|
| 135 | calc_min_width (HTMLObject *self, |
---|
| 136 | HTMLPainter *painter) |
---|
| 137 | { |
---|
| 138 | GtkRequisition requisition; |
---|
| 139 | GtkWidget *widget; |
---|
| 140 | gint pixel_size; |
---|
| 141 | gint min_width; |
---|
| 142 | |
---|
| 143 | widget = HTML_EMBEDDED (self)->widget; |
---|
| 144 | |
---|
[21115] | 145 | if (widget == NULL || !GTK_WIDGET_VISIBLE (widget)) |
---|
[19538] | 146 | return 0; |
---|
| 147 | |
---|
[21115] | 148 | requisition.width = requisition.height = 0; |
---|
[19538] | 149 | gtk_widget_size_request (widget, &requisition); |
---|
| 150 | pixel_size = html_painter_get_pixel_size (painter); |
---|
| 151 | |
---|
| 152 | min_width = requisition.width * pixel_size; |
---|
| 153 | |
---|
| 154 | return min_width; |
---|
| 155 | } |
---|
| 156 | |
---|
| 157 | static gboolean |
---|
[21115] | 158 | html_embedded_real_calc_size (HTMLObject *self, HTMLPainter *painter, GList **changed_objs) |
---|
[19538] | 159 | { |
---|
| 160 | GtkWidget *widget; |
---|
| 161 | HTMLEmbedded *emb = HTML_EMBEDDED (self); |
---|
| 162 | gint pixel_size; |
---|
| 163 | gint old_width, old_ascent, old_descent; |
---|
| 164 | GtkRequisition requisition; |
---|
| 165 | |
---|
| 166 | widget = emb->widget; |
---|
| 167 | if (widget == NULL) |
---|
| 168 | return FALSE; |
---|
| 169 | |
---|
| 170 | pixel_size = html_painter_get_pixel_size (painter); |
---|
| 171 | |
---|
| 172 | old_width = self->width; |
---|
| 173 | old_ascent = self->ascent; |
---|
| 174 | old_descent = self->descent; |
---|
| 175 | |
---|
[21115] | 176 | requisition.width = requisition.height = 0; |
---|
[19538] | 177 | gtk_widget_size_request (widget, &requisition); |
---|
| 178 | |
---|
| 179 | if (GTK_IS_HTML_EMBEDDED(widget)) |
---|
| 180 | self->descent = GTK_HTML_EMBEDDED (widget)->descent * pixel_size; |
---|
| 181 | else |
---|
| 182 | self->descent = 0; |
---|
| 183 | |
---|
| 184 | self->width = requisition.width * pixel_size; |
---|
| 185 | self->ascent = requisition.height * pixel_size - self->descent; |
---|
| 186 | |
---|
| 187 | if (old_width != self->width || old_ascent != self->ascent || old_ascent != self->descent) |
---|
| 188 | return TRUE; |
---|
| 189 | |
---|
| 190 | return FALSE; |
---|
| 191 | } |
---|
| 192 | |
---|
| 193 | static gboolean |
---|
| 194 | accepts_cursor (HTMLObject *o) |
---|
| 195 | { |
---|
| 196 | return TRUE; |
---|
| 197 | } |
---|
| 198 | |
---|
| 199 | static gchar * |
---|
| 200 | encode (HTMLEmbedded *e) |
---|
| 201 | { |
---|
| 202 | return g_strdup (""); |
---|
| 203 | } |
---|
| 204 | |
---|
| 205 | void |
---|
| 206 | html_embedded_reset (HTMLEmbedded *e) |
---|
| 207 | { |
---|
| 208 | HTML_EMBEDDED_CLASS (HTML_OBJECT (e)->klass)->reset (e); |
---|
| 209 | } |
---|
| 210 | |
---|
| 211 | gchar * |
---|
| 212 | html_embedded_encode (HTMLEmbedded *e) |
---|
| 213 | { |
---|
| 214 | return HTML_EMBEDDED_CLASS (HTML_OBJECT (e)->klass)->encode (e); |
---|
| 215 | } |
---|
| 216 | |
---|
| 217 | void |
---|
| 218 | html_embedded_reparent (HTMLEmbedded *e, GtkWidget *new_parent) |
---|
| 219 | { |
---|
| 220 | HTML_EMBEDDED_CLASS (HTML_OBJECT (e)->klass)->reparent (e, new_parent); |
---|
| 221 | } |
---|
| 222 | |
---|
| 223 | void |
---|
| 224 | html_embedded_set_form (HTMLEmbedded *e, HTMLForm *form) |
---|
| 225 | { |
---|
| 226 | e->form = form; |
---|
| 227 | } |
---|
| 228 | |
---|
| 229 | gchar * |
---|
| 230 | html_embedded_encode_string (const gchar *str) |
---|
| 231 | { |
---|
| 232 | static gchar *safe = "$-._!*(),"; /* RFC 1738 */ |
---|
| 233 | unsigned pos = 0; |
---|
| 234 | GString *encoded = g_string_new (""); |
---|
| 235 | gchar buffer[5], *ptr; |
---|
| 236 | guchar c; |
---|
| 237 | |
---|
| 238 | while ( pos < strlen(str) ) { |
---|
| 239 | |
---|
| 240 | c = (unsigned char) str[pos]; |
---|
| 241 | |
---|
| 242 | if ( (( c >= 'A') && ( c <= 'Z')) || |
---|
| 243 | (( c >= 'a') && ( c <= 'z')) || |
---|
| 244 | (( c >= '0') && ( c <= '9')) || |
---|
| 245 | (strchr(safe, c)) |
---|
| 246 | ) |
---|
| 247 | { |
---|
| 248 | encoded = g_string_append_c (encoded, c); |
---|
| 249 | } |
---|
| 250 | else if ( c == ' ' ) |
---|
| 251 | { |
---|
| 252 | encoded = g_string_append_c (encoded, '+'); |
---|
| 253 | } |
---|
| 254 | else if ( c == '\n' ) |
---|
| 255 | { |
---|
| 256 | encoded = g_string_append (encoded, "%0D%0A"); |
---|
| 257 | } |
---|
| 258 | else if ( c != '\r' ) |
---|
| 259 | { |
---|
| 260 | sprintf( buffer, "%%%02X", (int)c ); |
---|
| 261 | encoded = g_string_append (encoded, buffer); |
---|
| 262 | } |
---|
| 263 | pos++; |
---|
| 264 | } |
---|
| 265 | |
---|
| 266 | ptr = encoded->str; |
---|
| 267 | |
---|
| 268 | g_string_free (encoded, FALSE); |
---|
| 269 | |
---|
| 270 | return ptr; |
---|
| 271 | } |
---|
| 272 | |
---|
| 273 | void |
---|
| 274 | html_embedded_type_init (void) |
---|
| 275 | { |
---|
| 276 | html_embedded_class_init (&html_embedded_class, HTML_TYPE_EMBEDDED, sizeof (HTMLEmbedded)); |
---|
| 277 | } |
---|
| 278 | |
---|
| 279 | void |
---|
| 280 | html_embedded_class_init (HTMLEmbeddedClass *klass, |
---|
| 281 | HTMLType type, |
---|
| 282 | guint size) |
---|
| 283 | { |
---|
| 284 | HTMLObjectClass *object_class; |
---|
| 285 | |
---|
| 286 | g_return_if_fail (klass != NULL); |
---|
| 287 | |
---|
| 288 | object_class = HTML_OBJECT_CLASS (klass); |
---|
| 289 | html_object_class_init (object_class, type, size); |
---|
| 290 | |
---|
| 291 | /* HTMLEmbedded methods. */ |
---|
| 292 | klass->reset = reset; |
---|
| 293 | klass->encode = encode; |
---|
| 294 | |
---|
| 295 | /* HTMLObject methods. */ |
---|
| 296 | object_class->destroy = destroy; |
---|
| 297 | object_class->copy = copy; |
---|
| 298 | object_class->draw = draw; |
---|
| 299 | object_class->accepts_cursor = accepts_cursor; |
---|
[21115] | 300 | object_class->calc_size = html_embedded_real_calc_size; |
---|
[19538] | 301 | object_class->calc_min_width = calc_min_width; |
---|
| 302 | |
---|
| 303 | parent_class = &html_object_class; |
---|
| 304 | } |
---|
| 305 | |
---|
| 306 | void |
---|
| 307 | html_embedded_init (HTMLEmbedded *element, |
---|
| 308 | HTMLEmbeddedClass *klass, |
---|
| 309 | GtkWidget *parent, |
---|
| 310 | gchar *name, |
---|
| 311 | gchar *value) |
---|
| 312 | { |
---|
| 313 | HTMLObject *object; |
---|
| 314 | |
---|
[21115] | 315 | d (printf ("embedded %p init\n", element)); |
---|
| 316 | |
---|
[19538] | 317 | object = HTML_OBJECT (element); |
---|
| 318 | html_object_init (object, HTML_OBJECT_CLASS (klass)); |
---|
| 319 | |
---|
| 320 | element->form = NULL; |
---|
| 321 | if (name) |
---|
| 322 | element->name = g_strdup(name); |
---|
| 323 | else |
---|
| 324 | element->name = g_strdup(""); |
---|
| 325 | if (value) |
---|
| 326 | element->value = g_strdup(value); |
---|
| 327 | else |
---|
| 328 | element->value = g_strdup(""); |
---|
| 329 | element->widget = NULL; |
---|
| 330 | element->parent = parent; |
---|
| 331 | element->width = 0; |
---|
| 332 | element->height = 0; |
---|
| 333 | element->abs_x = element->abs_y = -1; |
---|
| 334 | element->changed_id = 0; |
---|
| 335 | } |
---|
| 336 | |
---|
| 337 | |
---|
| 338 | static gboolean |
---|
| 339 | html_embedded_grab_cursor(GtkWidget *eb, GdkEvent *event) |
---|
| 340 | { |
---|
| 341 | /* Keep the focus! Fight the power */ |
---|
| 342 | return TRUE; |
---|
| 343 | } |
---|
| 344 | |
---|
| 345 | /* called when some state in an embedded html object has changed ... do a redraw */ |
---|
| 346 | static void |
---|
| 347 | html_embedded_object_changed (GtkHTMLEmbedded *eb, HTMLEngine *e) |
---|
| 348 | { |
---|
| 349 | HTMLObject *object; |
---|
| 350 | |
---|
| 351 | object = HTML_OBJECT (g_object_get_data (G_OBJECT (eb), "embeddedelement")); |
---|
| 352 | if (object) |
---|
| 353 | html_object_calc_size (object, e->painter, FALSE); |
---|
| 354 | |
---|
| 355 | html_engine_schedule_update(e); |
---|
| 356 | } |
---|
| 357 | |
---|
| 358 | HTMLEmbedded * |
---|
| 359 | html_embedded_new_widget (GtkWidget *parent, GtkHTMLEmbedded *eb, HTMLEngine *engine) |
---|
| 360 | { |
---|
| 361 | HTMLEmbedded *em; |
---|
| 362 | |
---|
| 363 | em = g_new0(HTMLEmbedded, 1); |
---|
[21115] | 364 | d (printf ("embedded %p new widget\n", em)); |
---|
| 365 | |
---|
[19538] | 366 | html_embedded_init (em, HTML_EMBEDDED_CLASS (&html_embedded_class), parent, eb->name, ""); |
---|
| 367 | html_embedded_set_widget (em, GTK_WIDGET (eb)); |
---|
| 368 | |
---|
| 369 | /* pass em as the user_data so that the handler will disconnect |
---|
| 370 | * when the object is destoyed |
---|
| 371 | */ |
---|
| 372 | g_signal_connect(eb, "button_press_event", G_CALLBACK (html_embedded_grab_cursor), em); |
---|
| 373 | em->changed_id = g_signal_connect (eb, "changed", G_CALLBACK (html_embedded_object_changed), engine); |
---|
| 374 | /* printf ("id %u\n", em->changed_id); */ |
---|
| 375 | |
---|
| 376 | return em; |
---|
| 377 | } |
---|
| 378 | |
---|
| 379 | static void |
---|
| 380 | html_embedded_allocate (GtkWidget *w, GtkAllocation *allocation, HTMLEmbedded *e) |
---|
| 381 | { |
---|
| 382 | if (e->width != allocation->width || e->height != allocation->height) { |
---|
| 383 | if (e->width != allocation->width) { |
---|
| 384 | html_object_change_set (HTML_OBJECT (e), HTML_CHANGE_ALL_CALC); |
---|
| 385 | e->width = allocation->width; |
---|
| 386 | } |
---|
| 387 | e->height = allocation->height; |
---|
| 388 | |
---|
[21115] | 389 | if (GTK_IS_HTML (w->parent)) |
---|
| 390 | html_engine_schedule_update (GTK_HTML (w->parent)->engine); |
---|
[19538] | 391 | } |
---|
| 392 | } |
---|
| 393 | |
---|
| 394 | void |
---|
| 395 | html_embedded_set_widget (HTMLEmbedded *emb, GtkWidget *w) |
---|
| 396 | { |
---|
| 397 | emb->widget = w; |
---|
| 398 | |
---|
[21115] | 399 | d (printf ("set embedded widget: %p widget: %p\n", emb, w)); |
---|
[19538] | 400 | gtk_widget_show (w); |
---|
| 401 | |
---|
| 402 | g_object_set_data (G_OBJECT (w), "embeddedelement", emb); |
---|
| 403 | g_signal_connect (w, "size_allocate", G_CALLBACK (html_embedded_allocate), emb); |
---|
| 404 | } |
---|
| 405 | |
---|
| 406 | GtkWidget * |
---|
| 407 | html_embedded_get_widget (HTMLEmbedded *e) |
---|
| 408 | { |
---|
| 409 | return e->widget; |
---|
| 410 | } |
---|
| 411 | |
---|
| 412 | gboolean |
---|
| 413 | html_object_is_embedded (HTMLObject *o) |
---|
| 414 | { |
---|
| 415 | gboolean rv = FALSE; |
---|
| 416 | |
---|
| 417 | switch (o->klass->type) { |
---|
| 418 | case HTML_TYPE_EMBEDDED: |
---|
| 419 | case HTML_TYPE_TEXTINPUT: |
---|
| 420 | case HTML_TYPE_BUTTON: |
---|
| 421 | case HTML_TYPE_IMAGEINPUT: |
---|
| 422 | case HTML_TYPE_TEXTAREA: |
---|
| 423 | case HTML_TYPE_HIDDEN: |
---|
| 424 | case HTML_TYPE_RADIO: |
---|
| 425 | case HTML_TYPE_CHECKBOX: |
---|
| 426 | case HTML_TYPE_SELECT: |
---|
| 427 | case HTML_TYPE_IFRAME: |
---|
| 428 | case HTML_TYPE_FRAME: |
---|
| 429 | rv = TRUE; |
---|
| 430 | default: |
---|
| 431 | ; |
---|
| 432 | } |
---|
| 433 | |
---|
| 434 | return rv; |
---|
| 435 | } |
---|
| 436 | |
---|
| 437 | gboolean |
---|
| 438 | html_object_is_frame (HTMLObject *o) |
---|
| 439 | { |
---|
| 440 | return HTML_IS_FRAME (o) || HTML_IS_IFRAME (o); |
---|
| 441 | } |
---|