5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
26 * xtext, the text widget used by X-Chat. Peter Zelezny <zed@xchat.org>.
27 * GtkTextView. Copyright (C) 2000 Red Hat, Inc.
28 * GtkHex. Jaka Mocnik <jaka@gnu.org>.
29 * pango-layout.c: High-level layout driver. Copyright (C) 2000, 2001, 2006 Red Hat Software
35 #include "ui/gtk/old-gtk-compat.h"
39 #include "../isprint.h"
41 #include <epan/charsets.h>
42 #include <epan/packet.h>
43 #include <epan/prefs.h>
45 #include "packet_panes.h"
48 #define REFRESH_TIMEOUT 10
50 static GtkWidgetClass
*parent_class
= NULL
;
56 PangoContext
*context
;
58 PangoFontDescription
*font
;
65 #if GTK_CHECK_VERSION(3, 0, 0)
66 guint hscroll_policy
: 1;
67 guint vscroll_policy
: 1;
72 gboolean bold_highlight
;
76 packet_char_enc encoding
; /* ASCII or EBCDIC */
77 bytes_view_type format
; /* bytes in hex or bytes as bits */
78 guint8
*pd
; /* packet data */
79 int len
; /* length of packet data in bytes */
80 /* data-highlight (field, appendix, protocol) */
84 int per_line
; /* number of bytes shown per line */
85 int use_digits
; /* number of hex digits of byte offset */
88 #include "bytes_view.h"
90 typedef struct _BytesViewClass
92 GtkWidgetClass parent_class
;
94 void (*set_scroll_adjustments
)(BytesView
*, GtkAdjustment
*, GtkAdjustment
*);
98 static void bytes_view_set_scroll_adjustments(BytesView
*, GtkAdjustment
*, GtkAdjustment
*);
99 static void bytes_view_adjustment_set(BytesView
*);
102 bytes_view_init(BytesView
*bv
)
104 #ifdef WANT_PACKET_EDITOR
105 gtk_widget_set_can_focus(GTK_WIDGET(bv
), TRUE
);
109 bv
->encoding
= PACKET_CHAR_ENC_CHAR_ASCII
;
110 bv
->format
= BYTES_HEX
;
119 bytes_view_destroy(BytesView
*bv
)
126 g_source_remove(bv
->adj_tag
);
130 g_object_unref(G_OBJECT(bv
->vadj
));
134 g_object_unref(G_OBJECT(bv
->hadj
));
138 pango_font_description_free(bv
->font
);
142 g_object_unref(bv
->context
);
147 #if GTK_CHECK_VERSION(3, 0, 0)
149 bytes_view_destroy_widget(GtkWidget
*widget
)
151 bytes_view_destroy(BYTES_VIEW(widget
));
153 GTK_WIDGET_CLASS(parent_class
)->destroy(widget
);
159 bytes_view_destroy_object(GtkObject
*object
)
161 bytes_view_destroy(BYTES_VIEW(object
));
163 if (GTK_OBJECT_CLASS(parent_class
)->destroy
)
164 (*GTK_OBJECT_CLASS(parent_class
)->destroy
)(object
);
170 bytes_view_ensure_layout(BytesView
*bv
)
172 if (bv
->context
== NULL
) {
173 bv
->context
= gtk_widget_get_pango_context(GTK_WIDGET(bv
));
174 g_object_ref(bv
->context
);
178 PangoFontMetrics
*metrics
;
180 /* vte and xchat does it this way */
181 lang
= pango_context_get_language(bv
->context
);
182 metrics
= pango_context_get_metrics(bv
->context
, bv
->font
, lang
);
183 bv
->font_ascent
= pango_font_metrics_get_ascent(metrics
) / PANGO_SCALE
;
184 bv
->font_descent
= pango_font_metrics_get_descent(metrics
) / PANGO_SCALE
;
185 pango_font_metrics_unref(metrics
);
187 bv
->fontsize
= bv
->font_ascent
+ bv
->font_descent
;
189 g_assert(bv
->context
);
190 bytes_view_adjustment_set(bv
);
195 bytes_view_realize(GtkWidget
*widget
)
198 GdkWindowAttr attributes
;
199 GtkAllocation allocation
;
202 #if GTK_CHECK_VERSION(3, 0, 0)
203 GtkStyleContext
*context
;
206 _gtk_widget_set_realized_true(widget
);
207 bv
= BYTES_VIEW(widget
);
209 gtk_widget_get_allocation(widget
, &allocation
);
211 attributes
.window_type
= GDK_WINDOW_CHILD
;
212 attributes
.x
= allocation
.x
;
213 attributes
.y
= allocation
.y
;
214 attributes
.width
= allocation
.width
;
215 attributes
.height
= allocation
.height
;
216 attributes
.wclass
= GDK_INPUT_OUTPUT
;
217 attributes
.visual
= gtk_widget_get_visual(widget
);
218 attributes
.event_mask
= gtk_widget_get_events(widget
) | GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK
;
220 #if !GTK_CHECK_VERSION(3, 0, 0)
221 attributes
.colormap
= gtk_widget_get_colormap(widget
);
223 win
= gdk_window_new(gtk_widget_get_parent_window(widget
), &attributes
, GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
);
225 win
= gdk_window_new(gtk_widget_get_parent_window(widget
), &attributes
, GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
);
228 gtk_widget_set_window(widget
, win
);
230 #if GTK_CHECK_VERSION(3, 8, 0)
231 gtk_widget_register_window(widget
, win
);
233 gdk_window_set_user_data(win
, widget
);
236 #if !GTK_CHECK_VERSION(3, 0, 0) /* XXX, check */
237 gdk_window_set_back_pixmap(win
, NULL
, FALSE
);
240 #if GTK_CHECK_VERSION(3, 0, 0)
241 context
= gtk_widget_get_style_context(widget
);
242 gtk_style_context_add_class(context
, GTK_STYLE_CLASS_VIEW
);
243 /* gtk_style_context_add_class(context, GTK_STYLE_CLASS_ENTRY); */
245 #elif GTK_CHECK_VERSION(2, 20, 0)
246 gtk_widget_style_attach(widget
);
248 widget
->style
= gtk_style_attach(widget
->style
, win
);
250 bytes_view_ensure_layout(bv
);
254 bytes_view_unrealize(GtkWidget
*widget
)
256 BytesView
*bv
= BYTES_VIEW(widget
);
259 g_object_unref(bv
->context
);
262 /* if there are still events in the queue, this'll avoid segfault */
263 #if !GTK_CHECK_VERSION(3, 8, 0)
264 gdk_window_set_user_data(gtk_widget_get_window(widget
), NULL
);
267 if (parent_class
->unrealize
)
268 (*GTK_WIDGET_CLASS(parent_class
)->unrealize
)(widget
);
271 static GtkAdjustment
*
272 bytes_view_ensure_vadj(BytesView
*bv
)
274 if (bv
->vadj
== NULL
) {
275 bytes_view_set_scroll_adjustments(bv
, bv
->hadj
, bv
->vadj
);
276 g_assert(bv
->vadj
!= NULL
);
281 static GtkAdjustment
*
282 bytes_view_ensure_hadj(BytesView
*bv
)
284 if (bv
->hadj
== NULL
) {
285 bytes_view_set_scroll_adjustments(bv
, bv
->hadj
, bv
->vadj
);
286 g_assert(bv
->hadj
!= NULL
);
292 bytes_view_scroll(GtkWidget
*widget
, GdkEventScroll
*event
)
294 BytesView
*bv
= BYTES_VIEW(widget
);
298 if (event
->direction
== GDK_SCROLL_UP
) { /* mouse wheel pageUp */
299 bytes_view_ensure_vadj(bv
);
301 new_value
= gtk_adjustment_get_value(bv
->vadj
) - (gtk_adjustment_get_page_increment(bv
->vadj
) / 10);
302 if (new_value
< gtk_adjustment_get_lower(bv
->vadj
))
303 new_value
= gtk_adjustment_get_lower(bv
->vadj
);
304 gtk_adjustment_set_value(bv
->vadj
, new_value
);
306 } else if (event
->direction
== GDK_SCROLL_DOWN
) { /* mouse wheel pageDn */
307 bytes_view_ensure_vadj(bv
);
309 new_value
= gtk_adjustment_get_value(bv
->vadj
) + (gtk_adjustment_get_page_increment(bv
->vadj
) / 10);
310 if (new_value
> (gtk_adjustment_get_upper(bv
->vadj
) - gtk_adjustment_get_page_size(bv
->vadj
)))
311 new_value
= gtk_adjustment_get_upper(bv
->vadj
) - gtk_adjustment_get_page_size(bv
->vadj
);
312 gtk_adjustment_set_value(bv
->vadj
, new_value
);
318 bytes_view_allocate(GtkWidget
*widget
, GtkAllocation
*allocation
)
320 gtk_widget_set_allocation(widget
, allocation
);
322 if (gtk_widget_get_realized(widget
)) {
323 BytesView
*bv
= BYTES_VIEW(widget
);
325 gdk_window_move_resize(gtk_widget_get_window(widget
), allocation
->x
, allocation
->y
, allocation
->width
, allocation
->height
);
326 bytes_view_adjustment_set(bv
);
330 #if GTK_CHECK_VERSION(3, 0, 0)
332 bytes_view_get_preferred_width(GtkWidget
*widget _U_
, gint
*minimum
, gint
*natural
)
334 *minimum
= *natural
= 200;
338 bytes_view_get_preferred_height(GtkWidget
*widget _U_
, gint
*minimum
, gint
*natural
)
340 *minimum
= *natural
= 90;
346 bytes_view_size_request(GtkWidget
*widget _U_
, GtkRequisition
*requisition
)
348 requisition
->width
= 200;
349 requisition
->height
= 90;
354 _pango_runs_build(BytesView
*bv
, const char *str
, int len
)
358 PangoAttrList
*attrs
;
359 PangoAttrIterator
*iter
;
364 attrs
= pango_attr_list_new();
365 pango_attr_list_insert_before(attrs
, pango_attr_font_desc_new(bv
->font
));
367 iter
= pango_attr_list_get_iterator(attrs
);
369 run_list
= pango_itemize(bv
->context
, str
, 0, len
, attrs
, iter
);
371 for (tmp_list
= run_list
; tmp_list
; tmp_list
= tmp_list
->next
) {
372 PangoLayoutRun
*run
= g_slice_new(PangoLayoutRun
);
373 PangoItem
*run_item
= (PangoItem
*)tmp_list
->data
;
375 run
->item
= run_item
;
377 /* XXX pango_layout_get_item_properties(run_item, &state->properties); */
379 run
->glyphs
= pango_glyph_string_new();
380 pango_shape(str
+ run_item
->offset
, run_item
->length
, &run_item
->analysis
, run
->glyphs
);
382 runs
= g_slist_prepend(runs
, run
);
385 g_list_free(run_list
);
387 pango_attr_iterator_destroy(iter
);
388 pango_attr_list_unref(attrs
);
390 return g_slist_reverse(runs
);
394 _pango_glyph_string_to_pixels(PangoGlyphString
*glyphs
, PangoFont
*font _U_
)
396 #if PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 14
397 return pango_glyph_string_get_width(glyphs
) / PANGO_SCALE
;
399 PangoRectangle logical_rect
;
401 pango_glyph_string_extents(glyphs
, font
, NULL
, &logical_rect
);
402 /* pango_extents_to_pixels(&logical_rect, NULL); */
404 return (logical_rect
.width
/ PANGO_SCALE
);
409 xtext_draw_layout_line(cairo_t
*cr
, gint x
, gint y
, GSList
*runs
)
412 PangoLayoutRun
*run
= (PangoLayoutRun
*)runs
->data
;
414 cairo_move_to(cr
, x
, y
);
415 pango_cairo_show_glyph_string(cr
, run
->item
->analysis
.font
, run
->glyphs
);
417 x
+= _pango_glyph_string_to_pixels(run
->glyphs
, run
->item
->analysis
.font
);
424 _pango_runs_width(GSList
*runs
)
429 PangoLayoutRun
*run
= (PangoLayoutRun
*)runs
->data
;
431 width
+= _pango_glyph_string_to_pixels(run
->glyphs
, run
->item
->analysis
.font
);
438 _pango_runs_free(GSList
*runs
)
443 PangoLayoutRun
*run
= (PangoLayoutRun
*)list
->data
;
445 pango_item_free(run
->item
);
446 pango_glyph_string_free(run
->glyphs
);
447 g_slice_free(PangoLayoutRun
, run
);
454 typedef int bytes_view_line_cb(BytesView
*, void *data
, int x
, int arg1
, const char *str
, int len
);
457 bytes_view_flush_render(BytesView
*bv
, void *data
, int x
, int y
, const char *str
, int len
)
459 cairo_t
*cr
= (cairo_t
*)data
;
463 #if GTK_CHECK_VERSION(3, 0, 0)
464 GtkStyleContext
*context
;
465 GdkRGBA bg_color
, fg_color
;
471 line_runs
= _pango_runs_build(bv
, str
, len
);
475 #if GTK_CHECK_VERSION(3, 0, 0)
476 context
= gtk_widget_get_style_context(GTK_WIDGET(bv
));
479 if (bv
->state
== GTK_STATE_SELECTED
|| bv
->state
== GTK_STATE_INSENSITIVE
) {
480 str_width
= _pango_runs_width(line_runs
);
483 #if GTK_CHECK_VERSION(3, 0, 0)
484 gtk_style_context_get_background_color(context
, (GtkStateFlags
)( (bv
->state
== GTK_STATE_SELECTED
? GTK_STATE_FLAG_FOCUSED
: 0) | GTK_STATE_FLAG_SELECTED
), &bg_color
);
485 gdk_cairo_set_source_rgba(cr
, &bg_color
);
487 gdk_cairo_set_source_color(cr
, >k_widget_get_style(GTK_WIDGET(bv
))->base
[bv
->state
]);
489 cairo_rectangle(cr
, x
, y
- bv
->font_ascent
, str_width
, bv
->fontsize
);
494 #if GTK_CHECK_VERSION(3, 0, 0)
495 gtk_style_context_get_color(context
, (GtkStateFlags
)(GTK_STATE_FLAG_FOCUSED
| (bv
->state
== GTK_STATE_SELECTED
? GTK_STATE_FLAG_SELECTED
: GTK_STATE_FLAG_NORMAL
)), &fg_color
);
496 gdk_cairo_set_source_rgba(cr
, &fg_color
);
498 gdk_cairo_set_source_color(cr
, >k_widget_get_style(GTK_WIDGET(bv
))->text
[bv
->state
]);
500 str_width
= xtext_draw_layout_line(cr
, x
, y
, line_runs
)-x
;
502 _pango_runs_free(line_runs
);
508 _pango_runs_find_index(GSList
*runs
, int x_pos
, const char *str
)
513 PangoLayoutRun
*run
= (PangoLayoutRun
*)runs
->data
;
516 width
= _pango_glyph_string_to_pixels(run
->glyphs
, run
->item
->analysis
.font
);
518 if (x_pos
>= start_pos
&& x_pos
< start_pos
+ width
) {
519 gboolean char_trailing
;
522 pango_glyph_string_x_to_index(run
->glyphs
,
523 (char *) str
+ run
->item
->offset
, run
->item
->length
,
524 &run
->item
->analysis
,
525 (x_pos
- start_pos
) * PANGO_SCALE
,
526 &pos
, &char_trailing
);
528 return run
->item
->offset
+ pos
;
538 bytes_view_flush_pos(BytesView
*bv
, void *data
, int x
, int search_x
, const char *str
, int len
)
540 int *pos_x
= (int *)data
;
547 line_runs
= _pango_runs_build(bv
, str
, len
);
549 line_width
= _pango_runs_width(line_runs
);
551 if (x
<= search_x
&& x
+ line_width
> search_x
) {
552 int off_x
= search_x
- x
;
555 if ((pos_run
= _pango_runs_find_index(line_runs
, off_x
, str
)) != -1)
556 *pos_x
= (-*pos_x
) + pos_run
;
558 return -1; /* terminate */
562 _pango_runs_free(line_runs
);
568 bytes_view_render_state(BytesView
*bv
, int state
)
570 g_assert(state
== GTK_STATE_NORMAL
|| state
== GTK_STATE_SELECTED
|| state
== GTK_STATE_INSENSITIVE
);
572 if (bv
->bold_highlight
) {
573 pango_font_description_set_weight(bv
->font
,
574 (state
== GTK_STATE_SELECTED
) ? PANGO_WEIGHT_BOLD
: PANGO_WEIGHT_NORMAL
);
575 bv
->state
= GTK_STATE_NORMAL
;
580 #define BYTE_VIEW_SEP 8 /* insert a space every BYTE_VIEW_SEP bytes */
583 _bytes_view_line_common(BytesView
*bv
, void *data
, const int org_off
, int xx
, int arg1
, bytes_view_line_cb flush
)
585 static const guchar hexchars
[16] = {
586 '0', '1', '2', '3', '4', '5', '6', '7',
587 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
589 const guint8
*pd
= bv
->pd
;
590 const int len
= bv
->len
;
605 g_assert(org_off
>= 0);
607 scroll_x
= (int) gtk_adjustment_get_value(bytes_view_ensure_hadj(bv
));
609 state
= GTK_STATE_NORMAL
;
610 bytes_view_render_state(bv
, GTK_STATE_NORMAL
);
612 /* Print the line number */
616 c
= (org_off
>> (j
*4)) & 0xF;
617 str
[cur
++] = hexchars
[c
];
622 /* Print the hex bit */
623 for (byten
= 0, off
= org_off
; byten
< bv
->per_line
; byten
++) {
624 gboolean byte_highlighted
=
625 (off
>= bv
->start
[0] && off
< bv
->end
[0]) ||
626 (off
>= bv
->start
[1] && off
< bv
->end
[1]);
627 gboolean proto_byte_highlighted
=
628 (off
>= bv
->start
[2] && off
< bv
->end
[2]);
630 int state_cur
= (off
< len
&& byte_highlighted
) ?
632 (off
< len
&& proto_byte_highlighted
) ?
633 GTK_STATE_INSENSITIVE
:
636 if (state_cur
!= state
) {
637 /* ok, we want to put space, we prefer to put it in STATE_NORMAL or STATE_INSENSITIVE */
638 int space_now
= (state_cur
!= GTK_STATE_NORMAL
&& state_cur
!= GTK_STATE_INSENSITIVE
)
639 || state
== GTK_STATE_NORMAL
;
641 if (space_now
&& byten
) {
643 /* insert a space every BYTE_VIEW_SEP bytes */
644 if ((off
% BYTE_VIEW_SEP
) == 0)
648 if ((dx
= flush(bv
, data
, xx
- scroll_x
, arg1
, str
, cur
)) < 0)
652 bytes_view_render_state(bv
, state_cur
);
655 if (!space_now
&& byten
) {
657 /* insert a space every BYTE_VIEW_SEP bytes */
658 if ((off
% BYTE_VIEW_SEP
) == 0)
664 /* insert a space every BYTE_VIEW_SEP bytes */
665 if ((off
% BYTE_VIEW_SEP
) == 0)
670 switch (bv
->format
) {
672 str
[cur
++] = hexchars
[(pd
[off
] & 0xf0) >> 4];
673 str
[cur
++] = hexchars
[pd
[off
] & 0x0f];
677 for (j
= 7; j
>= 0; j
--)
678 str
[cur
++] = (pd
[off
] & (1 << j
)) ? '1' : '0';
682 switch (bv
->format
) {
688 for (j
= 7; j
>= 0; j
--)
696 if (state
!= GTK_STATE_NORMAL
) {
697 if ((dx
= flush(bv
, data
, xx
- scroll_x
, arg1
, str
, cur
)) < 0)
701 bytes_view_render_state(bv
, GTK_STATE_NORMAL
);
702 state
= GTK_STATE_NORMAL
;
705 /* Print some space at the end of the line */
706 str
[cur
++] = ' '; str
[cur
++] = ' '; str
[cur
++] = ' ';
708 /* Print the ASCII bit */
709 for (byten
= 0, off
= org_off
; byten
< bv
->per_line
; byten
++) {
710 gboolean byte_highlighted
=
711 (off
>= bv
->start
[0] && off
< bv
->end
[0]) ||
712 (off
>= bv
->start
[1] && off
< bv
->end
[1]);
713 gboolean proto_byte_highlighted
=
714 (off
>= bv
->start
[2] && off
< bv
->end
[2]);
716 int state_cur
= (off
< len
&& byte_highlighted
) ?
718 (off
< len
&& proto_byte_highlighted
) ?
719 GTK_STATE_INSENSITIVE
:
722 if (state_cur
!= state
) {
723 int space_now
= (state_cur
!= GTK_STATE_NORMAL
&& state_cur
!= GTK_STATE_INSENSITIVE
)
724 || state
== GTK_STATE_NORMAL
;
726 if (space_now
&& byten
) {
727 /* insert a space every BYTE_VIEW_SEP bytes */
728 if ((off
% BYTE_VIEW_SEP
) == 0)
732 if ((dx
= flush(bv
, data
, xx
- scroll_x
, arg1
, str
, cur
)) < 0)
736 bytes_view_render_state(bv
, state_cur
);
739 if (!space_now
&& byten
) {
740 /* insert a space every BYTE_VIEW_SEP bytes */
741 if ((off
% BYTE_VIEW_SEP
) == 0)
746 /* insert a space every BYTE_VIEW_SEP bytes */
747 if ((off
% BYTE_VIEW_SEP
) == 0)
752 c
= (bv
->encoding
== PACKET_CHAR_ENC_CHAR_EBCDIC
) ?
753 EBCDIC_to_ASCII1(pd
[off
]) :
756 str
[cur
++] = isprint(c
) ? c
: '.';
764 if ((dx
= flush(bv
, data
, xx
- scroll_x
, arg1
, str
, cur
)) < 0)
770 if (state
!= GTK_STATE_NORMAL
) {
771 bytes_view_render_state(bv
, GTK_STATE_NORMAL
);
772 /* state = GTK_STATE_NORMAL; */
775 if (bv
->max_width
< xx
)
780 _bytes_view_render_line(BytesView
*bv
, cairo_t
*cr
, const int org_off
, int yy
)
782 _bytes_view_line_common(bv
, cr
, org_off
, MARGIN
, yy
, bytes_view_flush_render
);
786 _bytes_view_find_pos(BytesView
*bv
, const int org_off
, int search_x
)
790 _bytes_view_line_common(bv
, &pos_x
, org_off
, MARGIN
, search_x
, bytes_view_flush_pos
);
796 bytes_view_render(BytesView
*bv
, cairo_t
*cr
, GdkRectangle
*area
)
798 const int old_max_width
= bv
->max_width
;
804 guint line
, lines_max
;
805 guint lines_max_full
;
807 #if GTK_CHECK_VERSION(3, 0, 0)
808 GtkStyleContext
*context
;
812 if (!gtk_widget_get_realized(GTK_WIDGET(bv
)))
815 bytes_view_ensure_layout(bv
);
817 #if GTK_CHECK_VERSION(3, 0, 0)
818 width
= gtk_widget_get_allocated_width(GTK_WIDGET(bv
));
819 height
= gtk_widget_get_allocated_height(GTK_WIDGET(bv
));
820 #elif GTK_CHECK_VERSION(2,24,0)
821 width
= gdk_window_get_width(gtk_widget_get_window(GTK_WIDGET(bv
)));
822 height
= gdk_window_get_height(gtk_widget_get_window(GTK_WIDGET(bv
)));
824 gdk_drawable_get_size(gtk_widget_get_window(GTK_WIDGET(bv
)), &width
, &height
);
827 if (width
< 32 + MARGIN
|| height
< bv
->fontsize
)
831 line
= area
->y
/ bv
->fontsize
;
832 lines_max
= 1 + (area
->y
+ area
->height
) / bv
->fontsize
;
835 lines_max
= (guint
) -1;
837 /* g_print("from %d to %d\n", line, lines_max); */
839 y
= (bv
->fontsize
* line
);
842 #if GTK_CHECK_VERSION(3, 0, 0)
843 context
= gtk_widget_get_style_context(GTK_WIDGET(bv
));
844 gtk_style_context_get_background_color(context
, (GtkStateFlags
)(GTK_STATE_FLAG_FOCUSED
| GTK_STATE_FLAG_NORMAL
), &bg_color
);
845 gdk_cairo_set_source_rgba(cr
, &bg_color
);
847 gdk_cairo_set_source_color(cr
, >k_widget_get_style(GTK_WIDGET(bv
))->base
[GTK_STATE_NORMAL
]);
850 cairo_rectangle(cr
, area
->x
, area
->y
, area
->x
+ area
->width
, area
->y
+ area
->height
);
852 cairo_rectangle(cr
, 0, 0, width
, height
);
856 guint real_line
= line
+ (guint
) gtk_adjustment_get_value(bytes_view_ensure_vadj(bv
));
858 lines_max_full
= (height
/ bv
->fontsize
) + 1;
859 if (lines_max_full
< lines_max
)
860 lines_max
= lines_max_full
;
862 off
= real_line
* bv
->per_line
;
864 while (off
< bv
->len
) {
865 _bytes_view_render_line(bv
, cr
, off
, y
+ bv
->font_ascent
);
867 if (line
>= lines_max
)
875 if (old_max_width
!= bv
->max_width
)
876 bytes_view_adjustment_set(bv
);
880 bytes_view_render_full(BytesView
*bv
)
885 g_source_remove(bv
->adj_tag
);
889 cr
= gdk_cairo_create(gtk_widget_get_window(GTK_WIDGET(bv
)));
890 bytes_view_render(bv
, cr
, NULL
);
894 #if GTK_CHECK_VERSION(3, 0, 0)
896 bytes_view_draw(GtkWidget
*widget
, cairo_t
*cr
)
900 gdk_cairo_get_clip_rectangle(cr
, &area
);
902 bytes_view_render(BYTES_VIEW(widget
), cr
, &area
);
909 bytes_view_expose(GtkWidget
*widget
, GdkEventExpose
*event
)
911 BytesView
*bv
= BYTES_VIEW(widget
);
914 cr
= gdk_cairo_create(gtk_widget_get_window(GTK_WIDGET(bv
)));
916 gdk_cairo_region(cr
, event
->region
);
919 bytes_view_render(bv
, cr
, &event
->area
);
927 #if !GTK_CHECK_VERSION(2, 14, 0)
929 _gtk_adjustment_configure(GtkAdjustment
*adj
,
933 gdouble step_increment
,
934 gdouble page_increment
,
940 adj
->step_increment
= step_increment
;
941 adj
->page_increment
= page_increment
;
942 adj
->page_size
= page_size
;
944 gtk_adjustment_changed(adj
);
947 #elif GTK_CHECK_VERSION(3, 0, 0)
949 #define _gtk_adjustment_configure(adj, val, low, up, step, page, size) \
950 gtk_adjustment_configure(adj, val, low, MAX((up), (size)), step, page, size)
954 #define _gtk_adjustment_configure(adj, val, low, up, step, page, size) \
955 gtk_adjustment_configure(adj, val, low, up, step, page, size)
961 bytes_view_adjustment_set(BytesView
*bv
)
963 GtkAllocation allocation
;
964 double lower
, upper
, page_size
, step_increment
, page_increment
, value
;
966 if (bv
->vadj
== NULL
|| bv
->hadj
== NULL
)
969 if (bv
->context
== NULL
) {
970 bytes_view_ensure_layout(bv
);
971 /* bytes_view_ensure_layout will call bytes_view_adjustment_set() again */
975 gtk_widget_get_allocation(GTK_WIDGET(bv
), &allocation
);
979 upper
= (int) (bv
->len
/ bv
->per_line
);
980 if ((bv
->len
% bv
->per_line
))
983 page_size
= (allocation
.height
- bv
->font_descent
) / bv
->fontsize
;
984 page_increment
= page_size
;
987 value
= gtk_adjustment_get_value(bv
->vadj
);
989 if (value
> upper
- page_size
)
990 value
= upper
- page_size
;
995 _gtk_adjustment_configure(bv
->vadj
, value
, lower
, upper
, step_increment
, page_increment
, page_size
);
1000 upper
= bv
->max_width
;
1002 page_size
= allocation
.width
;
1003 page_increment
= page_size
;
1004 step_increment
= page_size
/ 10.0;
1006 value
= gtk_adjustment_get_value(bv
->hadj
);
1008 if (value
> upper
- page_size
)
1009 value
= upper
- page_size
;
1014 _gtk_adjustment_configure(bv
->hadj
, value
, lower
, upper
, step_increment
, page_increment
, page_size
);
1019 bytes_view_adjustment_timeout(BytesView
*bv
)
1022 bytes_view_render_full(bv
);
1027 bytes_view_adjustment_changed(GtkAdjustment
*adj
, BytesView
*bv
)
1029 /* delay rendering when scrolling (10ms) */
1030 if (adj
&& ((adj
== bv
->vadj
) || (adj
== bv
->hadj
))) {
1032 bv
->adj_tag
= g_timeout_add(REFRESH_TIMEOUT
, (GSourceFunc
) bytes_view_adjustment_timeout
, bv
);
1037 bytes_view_set_scroll_adjustments(BytesView
*bv
, GtkAdjustment
*hadj
, GtkAdjustment
*vadj
)
1039 gboolean need_adjust
= FALSE
;
1041 g_return_if_fail(!hadj
|| GTK_IS_ADJUSTMENT(hadj
));
1042 g_return_if_fail(!vadj
|| GTK_IS_ADJUSTMENT(vadj
));
1045 vadj
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1048 hadj
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1050 if (bv
->vadj
&& (bv
->vadj
!= vadj
)) {
1051 g_signal_handlers_disconnect_by_func(bv
->vadj
, bytes_view_adjustment_changed
, bv
);
1052 g_object_unref(bv
->vadj
);
1054 if (bv
->vadj
!= vadj
) {
1056 g_object_ref_sink(bv
->vadj
);
1058 g_signal_connect(bv
->vadj
, "value-changed", G_CALLBACK(bytes_view_adjustment_changed
), bv
);
1060 #if GTK_CHECK_VERSION(3, 0, 0)
1061 g_object_notify(G_OBJECT(bv
), "vadjustment");
1065 if (bv
->hadj
&& (bv
->hadj
!= hadj
)) {
1066 g_signal_handlers_disconnect_by_func(bv
->hadj
, bytes_view_adjustment_changed
, bv
);
1067 g_object_unref(bv
->hadj
);
1069 if (bv
->hadj
!= hadj
) {
1071 g_object_ref_sink(bv
->hadj
);
1073 g_signal_connect(bv
->hadj
, "value-changed", G_CALLBACK(bytes_view_adjustment_changed
), bv
);
1075 #if GTK_CHECK_VERSION(3, 0, 0)
1076 g_object_notify(G_OBJECT(bv
), "hadjustment");
1081 bytes_view_adjustment_set(bv
);
1084 #if GTK_CHECK_VERSION(3, 0, 0)
1089 PROP_HSCROLL_POLICY
,
1094 bytes_view_set_property(GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
1096 BytesView
*bv
= BYTES_VIEW(object
);
1099 case PROP_HADJUSTMENT
:
1100 bytes_view_set_scroll_adjustments(bv
, (GtkAdjustment
*)g_value_get_object(value
), bv
->vadj
);
1103 case PROP_VADJUSTMENT
:
1104 bytes_view_set_scroll_adjustments(bv
, bv
->hadj
, (GtkAdjustment
*)g_value_get_object(value
));
1107 case PROP_HSCROLL_POLICY
:
1108 bv
->hscroll_policy
= g_value_get_enum(value
);
1109 gtk_widget_queue_resize(GTK_WIDGET(bv
));
1112 case PROP_VSCROLL_POLICY
:
1113 bv
->vscroll_policy
= g_value_get_enum(value
);
1114 gtk_widget_queue_resize(GTK_WIDGET(bv
));
1118 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
1124 bytes_view_get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
1126 BytesView
*bv
= BYTES_VIEW(object
);
1129 case PROP_HADJUSTMENT
:
1130 g_value_set_object(value
, bv
->hadj
);
1133 case PROP_VADJUSTMENT
:
1134 g_value_set_object(value
, bv
->vadj
);
1137 case PROP_HSCROLL_POLICY
:
1138 g_value_set_enum(value
, bv
->hscroll_policy
);
1141 case PROP_VSCROLL_POLICY
:
1142 g_value_set_enum(value
, bv
->vscroll_policy
);
1146 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
1153 /* bv_VOID__OBJECT_OBJECT() generated by:
1154 * $ echo 'VOID:OBJECT,OBJECT' | glib-genmarshal --prefix=bv --body
1155 * (glib-genmarshal version 2.32.4)
1156 * I *really hope* it's portable over platforms and can be put generated.
1160 bv_VOID__OBJECT_OBJECT(GClosure
*closure
, GValue
*return_value _U_
, guint n_params
, const GValue
*param_values
, gpointer hint _U_
, gpointer marshal_data
)
1162 typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT
)(gpointer
, gpointer
, gpointer
, gpointer
);
1164 register GMarshalFunc_VOID__OBJECT_OBJECT callback
;
1165 register GCClosure
*cc
= (GCClosure
*) closure
;
1166 register gpointer data1
, data2
;
1168 g_return_if_fail(n_params
== 3);
1170 if (G_CCLOSURE_SWAP_DATA(closure
)) {
1171 data1
= closure
->data
;
1172 data2
= g_value_peek_pointer(param_values
+ 0);
1174 data1
= g_value_peek_pointer(param_values
+ 0);
1175 data2
= closure
->data
;
1177 callback
= (GMarshalFunc_VOID__OBJECT_OBJECT
) (marshal_data
? marshal_data
: cc
->callback
);
1179 callback(data1
, g_value_get_object(param_values
+ 1), g_value_get_object(param_values
+ 2), data2
);
1185 bytes_view_class_init(BytesViewClass
*klass
)
1187 #if !GTK_CHECK_VERSION(3, 0, 0)
1188 GtkObjectClass
*object_class
;
1190 GtkWidgetClass
*widget_class
;
1192 parent_class
= (GtkWidgetClass
*) g_type_class_peek_parent(klass
);
1194 #if !GTK_CHECK_VERSION(3, 0, 0)
1195 object_class
= (GtkObjectClass
*) klass
;
1197 widget_class
= (GtkWidgetClass
*) klass
;
1199 #if GTK_CHECK_VERSION(3, 0, 0)
1200 widget_class
->destroy
= bytes_view_destroy_widget
;
1202 object_class
->destroy
= bytes_view_destroy_object
;
1204 widget_class
->realize
= bytes_view_realize
;
1205 widget_class
->unrealize
= bytes_view_unrealize
;
1206 #if GTK_CHECK_VERSION(3, 0, 0)
1207 widget_class
->get_preferred_width
= bytes_view_get_preferred_width
;
1208 widget_class
->get_preferred_height
= bytes_view_get_preferred_height
;
1210 widget_class
->size_request
= bytes_view_size_request
;
1212 widget_class
->size_allocate
= bytes_view_allocate
;
1214 #if GTK_CHECK_VERSION(3, 0, 0)
1215 widget_class
->draw
= bytes_view_draw
;
1217 widget_class
->expose_event
= bytes_view_expose
;
1220 widget_class
->scroll_event
= bytes_view_scroll
;
1222 #if GTK_CHECK_VERSION(3, 0, 0)
1224 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1226 gobject_class
->set_property
= bytes_view_set_property
;
1227 gobject_class
->get_property
= bytes_view_get_property
;
1229 /* XXX, move some code from widget->destroy to gobject->finalize? */
1230 /* gobject_class->finalize = bytes_view_finalize; */
1232 g_object_class_override_property(gobject_class
, PROP_HADJUSTMENT
, "hadjustment");
1233 g_object_class_override_property(gobject_class
, PROP_VADJUSTMENT
, "vadjustment");
1234 g_object_class_override_property(gobject_class
, PROP_HSCROLL_POLICY
, "hscroll-policy");
1235 g_object_class_override_property(gobject_class
, PROP_VSCROLL_POLICY
, "vscroll-policy");
1238 klass
->set_scroll_adjustments
= bytes_view_set_scroll_adjustments
;
1240 widget_class
->set_scroll_adjustments_signal
=
1241 g_signal_new(g_intern_static_string("set-scroll-adjustments"),
1242 G_OBJECT_CLASS_TYPE(object_class
),
1243 (GSignalFlags
)(G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
),
1244 G_STRUCT_OFFSET(BytesViewClass
, set_scroll_adjustments
),
1246 bv_VOID__OBJECT_OBJECT
,
1248 GTK_TYPE_ADJUSTMENT
,
1249 GTK_TYPE_ADJUSTMENT
);
1254 bytes_view_get_type(void)
1256 static GType bytes_view_gtype
= 0;
1258 if (!bytes_view_gtype
) {
1259 static const GTypeInfo bytes_view_info
= {
1260 sizeof (BytesViewClass
),
1261 NULL
, /* base_init */
1262 NULL
, /* base_finalize */
1263 (GClassInitFunc
) bytes_view_class_init
,
1264 NULL
, /* class finalize */
1265 NULL
, /* class_data */
1267 0, /* n_preallocs */
1268 (GInstanceInitFunc
) bytes_view_init
,
1269 NULL
/* value_table */
1272 #if GTK_CHECK_VERSION(3, 0, 0)
1273 static const GInterfaceInfo scrollable_info
= {
1280 bytes_view_gtype
= g_type_register_static(GTK_TYPE_WIDGET
,
1285 #if GTK_CHECK_VERSION(3, 0, 0)
1286 g_type_add_interface_static(bytes_view_gtype
,
1287 GTK_TYPE_SCROLLABLE
,
1291 return bytes_view_gtype
;
1295 bytes_view_byte_from_xy(BytesView
*bv
, int x
, int y
)
1297 /* hex_pos_byte array generated with hex_view_get_byte(0, 0, 0...70) */
1298 static const int hex_pos_byte
[70] = {
1300 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3,
1301 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7,
1303 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11,
1304 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15,
1306 0, 1, 2, 3, 4, 5, 6, 7,
1308 8, 9, 10, 11, 12, 13, 14, 15
1311 /* bits_pos_byte array generated with bit_view_get_byte(0, 0, 0...84) */
1312 static const int bits_pos_byte
[84] = {
1314 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1315 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1316 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
1317 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
1319 0, 1, 2, 3, 4, 5, 6, 7
1322 int char_x
, off_x
= 1;
1328 bytes_view_ensure_layout(bv
);
1330 char_y
= (int) gtk_adjustment_get_value(bytes_view_ensure_vadj(bv
)) + (y
/ bv
->fontsize
);
1331 off_y
= char_y
* bv
->per_line
;
1333 char_x
= _bytes_view_find_pos(bv
, off_y
, x
);
1334 if (/* char_x < 0 || */ char_x
< bv
->use_digits
)
1336 char_x
-= bv
->use_digits
;
1338 switch (bv
->format
) {
1340 g_return_val_if_fail(char_x
>= 0 && char_x
< (int) G_N_ELEMENTS(bits_pos_byte
), -1);
1341 off_x
= bits_pos_byte
[char_x
];
1345 g_return_val_if_fail(char_x
>= 0 && char_x
< (int) G_N_ELEMENTS(hex_pos_byte
), -1);
1346 off_x
= hex_pos_byte
[char_x
];
1353 return off_y
+ off_x
;
1357 bytes_view_scroll_to_byte(BytesView
*bv
, int byte
)
1361 g_return_if_fail(byte
>= 0 && byte
< bv
->len
);
1363 line
= byte
/ bv
->per_line
;
1365 bytes_view_ensure_vadj(bv
);
1367 if (line
> gtk_adjustment_get_upper(bv
->vadj
) - gtk_adjustment_get_page_size(bv
->vadj
)) {
1368 line
= (int)(gtk_adjustment_get_upper(bv
->vadj
) - gtk_adjustment_get_page_size(bv
->vadj
));
1374 /* after bytes_view_scroll_to_byte() we always do bytes_view_refresh() so we can block it */
1375 g_signal_handlers_block_by_func(bv
->vadj
, bytes_view_adjustment_changed
, bv
);
1376 gtk_adjustment_set_value(bv
->vadj
, line
);
1377 g_signal_handlers_unblock_by_func(bv
->vadj
, bytes_view_adjustment_changed
, bv
);
1379 /* XXX, scroll hadj? */
1383 bytes_view_set_font(BytesView
*bv
, PangoFontDescription
*font
)
1386 pango_font_description_free(bv
->font
);
1388 #if GTK_CHECK_VERSION(3, 0, 0)
1389 gtk_widget_override_font(GTK_WIDGET(bv
), font
);
1391 gtk_widget_modify_font(GTK_WIDGET(bv
), font
);
1393 bv
->font
= pango_font_description_copy(font
);
1397 g_object_unref(bv
->context
);
1399 bytes_view_ensure_layout(bv
);
1404 bytes_view_set_data(BytesView
*bv
, const guint8
*data
, int len
)
1407 bv
->pd
= (guint8
*)g_memdup(data
, len
);
1411 * How many of the leading digits of the offset will we supply?
1412 * We always supply at least 4 digits, but if the maximum offset
1413 * won't fit in 4 digits, we use as many digits as will be needed.
1415 if (((len
- 1) & 0xF0000000) != 0)
1416 bv
->use_digits
= 8; /* need all 8 digits */
1417 else if (((len
- 1) & 0x0F000000) != 0)
1418 bv
->use_digits
= 7; /* need 7 digits */
1419 else if (((len
- 1) & 0x00F00000) != 0)
1420 bv
->use_digits
= 6; /* need 6 digits */
1421 else if (((len
- 1) & 0x000F0000) != 0)
1422 bv
->use_digits
= 5; /* need 5 digits */
1424 bv
->use_digits
= 4; /* we'll supply 4 digits */
1426 bytes_view_ensure_vadj(bv
);
1428 bytes_view_adjustment_set(bv
);
1432 bytes_view_set_encoding(BytesView
*bv
, int enc
)
1434 g_assert(enc
== PACKET_CHAR_ENC_CHAR_ASCII
|| enc
== PACKET_CHAR_ENC_CHAR_EBCDIC
);
1436 bv
->encoding
= (packet_char_enc
)enc
;
1440 bytes_view_set_format(BytesView
*bv
, int format
)
1442 g_assert(format
== BYTES_HEX
|| format
== BYTES_BITS
);
1444 bv
->format
= (bytes_view_type
)format
;
1458 bytes_view_set_highlight_style(BytesView
*bv
, gboolean inverse
)
1460 bv
->bold_highlight
= !inverse
;
1464 bytes_view_set_highlight(BytesView
*bv
, int start
, int end
, guint32 mask _U_
, int maskle _U_
)
1466 bv
->start
[0] = start
;
1471 bytes_view_set_highlight_extra(BytesView
*bv
, int id
, int start
, int end
)
1473 bv
->start
[id
] = start
;
1478 bytes_view_refresh(BytesView
*bv
)
1480 /* bytes_view_render_full(bv); */
1481 gtk_widget_queue_draw(GTK_WIDGET(bv
));
1485 bytes_view_new(void)
1489 widget
= (GtkWidget
*) g_object_new(BYTES_VIEW_TYPE
, NULL
);
1491 g_assert(widget
!= NULL
);