comparison src/pixbuf-renderer.c @ 104:8d358a53146e

Wed Nov 8 16:59:14 2006 John Ellis <johne@verizon.net> * pixbuf-renderer.[ch]: Give image overlays their own child GdkWindow, and use a buffer when drawing to those windows to avoid flicker. Scrolling with the info [I] visible in full screen is now much smoother. Only one regression that will be fixed later: overlapping overlays are now ugly.
author gqview
date Wed, 08 Nov 2006 22:07:26 +0000
parents d19b0de6d0bb
children 98e2632b5d3d
comparison
equal deleted inserted replaced
103:61e57ef42cf8 104:8d358a53146e
1 /* 1 /*
2 * GQview 2 * GQview
3 * (C) 2005 John Ellis 3 * (C) 2006 John Ellis
4 * 4 *
5 * Author: John Ellis 5 * Author: John Ellis
6 * 6 *
7 * This software is released under the GNU General Public License (GNU GPL). 7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information. 8 * Please read the included file COPYING for more information.
120 struct _OverlayData 120 struct _OverlayData
121 { 121 {
122 gint id; 122 gint id;
123 123
124 GdkPixbuf *pixbuf; 124 GdkPixbuf *pixbuf;
125 GdkWindow *window;
125 126
126 gint x; 127 gint x;
127 gint y; 128 gint y;
128 gint relative; /* x,y coordinates are relative, negative values start bottom right */ 129 gint relative; /* x,y coordinates are relative, negative values start bottom right */
129 130
130 gint visible; 131 gint always; /* hide temporarily when scrolling (not yet implemented) */
131 gint always; /* hide temporarily when scrolling */
132 }; 132 };
133 133
134 enum { 134 enum {
135 SIGNAL_ZOOM = 0, 135 SIGNAL_ZOOM = 0,
136 SIGNAL_CLICKED, 136 SIGNAL_CLICKED,
609 { 609 {
610 if (GTK_WIDGET_DRAWABLE(widget)) 610 if (GTK_WIDGET_DRAWABLE(widget))
611 { 611 {
612 if (!GTK_WIDGET_NO_WINDOW(widget)) 612 if (!GTK_WIDGET_NO_WINDOW(widget))
613 { 613 {
614 pixbuf_renderer_paint(PIXBUF_RENDERER(widget), &event->area); 614 if (event->window != widget->window)
615 {
616 GdkRectangle area;
617
618 gdk_window_get_position(event->window, &area.x, &area.y);
619
620 area.x += event->area.x;
621 area.y += event->area.y;
622 area.width = event->area.width;
623 area.height = event->area.height;
624 pixbuf_renderer_paint(PIXBUF_RENDERER(widget), &area);
625 }
626 else
627 {
628 pixbuf_renderer_paint(PIXBUF_RENDERER(widget), &event->area);
629 }
615 } 630 }
616 } 631 }
617 632
618 return FALSE; 633 return FALSE;
619 } 634 }
740 *------------------------------------------------------------------- 755 *-------------------------------------------------------------------
741 * overlays 756 * overlays
742 *------------------------------------------------------------------- 757 *-------------------------------------------------------------------
743 */ 758 */
744 759
745 static void pr_overlay_draw(PixbufRenderer *pr, gint x, gint y, gint w, gint h) 760 static void pr_overlay_get_position(PixbufRenderer *pr, OverlayData *od,
761 gint *x, gint *y, gint *w, gint *h)
762 {
763 gint px, py, pw, ph;
764
765 pw = gdk_pixbuf_get_width(od->pixbuf);
766 ph = gdk_pixbuf_get_height(od->pixbuf);
767 px = od->x;
768 py = od->y;
769
770 if (od->relative)
771 {
772 if (px < 0) px = pr->window_width - pw + px;
773 if (py < 0) py = pr->window_height - ph + py;
774 }
775
776 if (x) *x = px;
777 if (y) *y = py;
778 if (w) *w = pw;
779 if (h) *h = ph;
780 }
781
782 static void pr_overlay_draw(PixbufRenderer *pr, gint x, gint y, gint w, gint h,
783 ImageTile *it)
746 { 784 {
747 GtkWidget *box; 785 GtkWidget *box;
748 GList *work; 786 GList *work;
749 787
750 box = GTK_WIDGET(pr); 788 box = GTK_WIDGET(pr);
757 gint rx, ry, rw, rh; 795 gint rx, ry, rw, rh;
758 796
759 od = work->data; 797 od = work->data;
760 work = work->next; 798 work = work->next;
761 799
762 if (!od->visible) continue; 800 pr_overlay_get_position(pr, od, &px, &py, &pw, &ph);
763
764 pw = gdk_pixbuf_get_width(od->pixbuf);
765 ph = gdk_pixbuf_get_height(od->pixbuf);
766 px = od->x;
767 py = od->y;
768
769 if (od->relative)
770 {
771 if (px < 0) px = pr->window_width - pw + px;
772 if (py < 0) py = pr->window_height - ph + py;
773 }
774
775 if (pr_clip_region(x, y, w, h, px, py, pw, ph, &rx, &ry, &rw, &rh)) 801 if (pr_clip_region(x, y, w, h, px, py, pw, ph, &rx, &ry, &rw, &rh))
776 { 802 {
777 gdk_draw_pixbuf(box->window, 803 if (!pr->overlay_buffer)
778 box->style->fg_gc[GTK_WIDGET_STATE(box)], 804 {
779 od->pixbuf, 805 pr->overlay_buffer = gdk_pixmap_new(((GtkWidget *)pr)->window, pr->tile_width, pr->tile_height, -1);
780 rx - px, ry - py, 806 }
781 rx, ry, rw, rh, 807
782 pr->dither_quality, rx, ry); 808 if (it)
783 } 809 {
784 } 810 gdk_draw_drawable(pr->overlay_buffer, box->style->fg_gc[GTK_WIDGET_STATE(box)],
785 } 811 it->pixmap,
786 812 rx - (pr->x_offset + (it->x - pr->x_scroll)),
787 static void pr_overlay_queue_draw(PixbufRenderer *pr, OverlayData *od, gint hidden) 813 ry - (pr->y_offset + (it->y - pr->y_scroll)),
814 0, 0, rw, rh);
815 gdk_draw_pixbuf(pr->overlay_buffer,
816 box->style->fg_gc[GTK_WIDGET_STATE(box)],
817 od->pixbuf,
818 rx - px, ry - py,
819 0, 0, rw, rh,
820 pr->dither_quality, rx, ry);
821 gdk_draw_drawable(od->window, box->style->fg_gc[GTK_WIDGET_STATE(box)],
822 pr->overlay_buffer,
823 0, 0,
824 rx - px, ry - py, rw, rh);
825 }
826 else
827 {
828 /* no ImageTile means region may be larger than our scratch buffer */
829 gint sx, sy;
830
831 for (sx = rx; sx < rx + rw; sx += pr->tile_width)
832 for(sy = ry; sy < ry + rh; sy += pr->tile_height)
833 {
834 gint sw, sh;
835
836 sw = MIN(rx + rw - sx, pr->tile_width);
837 sh = MIN(ry + rh - sy, pr->tile_height);
838
839 gdk_draw_rectangle(pr->overlay_buffer,
840 box->style->bg_gc[GTK_WIDGET_STATE(box)], TRUE,
841 0, 0, sw, sh);
842 gdk_draw_pixbuf(pr->overlay_buffer,
843 box->style->fg_gc[GTK_WIDGET_STATE(box)],
844 od->pixbuf,
845 sx - px, sy - py,
846 0, 0, sw, sh,
847 pr->dither_quality, sx, sy);
848 gdk_draw_drawable(od->window, box->style->fg_gc[GTK_WIDGET_STATE(box)],
849 pr->overlay_buffer,
850 0, 0,
851 sx - px, sy - py, sw, sh);
852 }
853 }
854 }
855 }
856 }
857
858 static void pr_overlay_queue_draw(PixbufRenderer *pr, OverlayData *od)
788 { 859 {
789 gint x, y, w, h; 860 gint x, y, w, h;
790 gint old_vis; 861
791 862 pr_overlay_get_position(pr, od, &x, &y, &w, &h);
792 w = gdk_pixbuf_get_width(od->pixbuf);
793 h = gdk_pixbuf_get_height(od->pixbuf);
794 x = od->x;
795 y = od->y;
796
797 if (od->relative)
798 {
799 if (x < 0) x = pr->window_width - w + x;
800 if (y < 0) y = pr->window_height - h + y;
801 }
802
803 pr_queue(pr, pr->x_scroll - pr->x_offset + x, 863 pr_queue(pr, pr->x_scroll - pr->x_offset + x,
804 pr->y_scroll - pr->y_offset + y, 864 pr->y_scroll - pr->y_offset + y,
805 w, h, 865 w, h,
806 FALSE, TILE_RENDER_ALL, FALSE, FALSE); 866 FALSE, TILE_RENDER_ALL, FALSE, FALSE);
807 867
808 old_vis = od->visible;
809 if (hidden) od->visible = FALSE;
810 pr_border_draw(pr, x, y, w, h); 868 pr_border_draw(pr, x, y, w, h);
811 od->visible = old_vis;
812 } 869 }
813 870
814 static void pr_overlay_queue_all(PixbufRenderer *pr) 871 static void pr_overlay_queue_all(PixbufRenderer *pr)
815 { 872 {
816 GList *work; 873 GList *work;
819 while (work) 876 while (work)
820 { 877 {
821 OverlayData *od = work->data; 878 OverlayData *od = work->data;
822 work = work->next; 879 work = work->next;
823 880
824 pr_overlay_queue_draw(pr, od, FALSE); 881 pr_overlay_queue_draw(pr, od);
825 } 882 }
826 } 883 }
827 884
828 static OverlayData *pr_overlay_find(PixbufRenderer *pr, gint id) 885 static void pr_overlay_update_sizes(PixbufRenderer *pr)
829 { 886 {
830 GList *work; 887 GList *work;
831 888
832 work = pr->overlay_list; 889 work = pr->overlay_list;
833 while (work) 890 while (work)
834 { 891 {
835 OverlayData *od = work->data; 892 OverlayData *od = work->data;
836 work = work->next; 893 work = work->next;
837 894
895 if (od->relative && od->window)
896 {
897 gint x, y, w, h;
898
899 pr_overlay_get_position(pr, od, &x, &y, &w, &h);
900 gdk_window_move_resize(od->window, x, y, w, h);
901 }
902 }
903 }
904
905 static OverlayData *pr_overlay_find(PixbufRenderer *pr, gint id)
906 {
907 GList *work;
908
909 work = pr->overlay_list;
910 while (work)
911 {
912 OverlayData *od = work->data;
913 work = work->next;
914
838 if (od->id == id) return od; 915 if (od->id == id) return od;
839 } 916 }
840 917
841 return NULL; 918 return NULL;
842 } 919 }
844 gint pixbuf_renderer_overlay_add(PixbufRenderer *pr, GdkPixbuf *pixbuf, gint x, gint y, 921 gint pixbuf_renderer_overlay_add(PixbufRenderer *pr, GdkPixbuf *pixbuf, gint x, gint y,
845 gint relative, gint always) 922 gint relative, gint always)
846 { 923 {
847 OverlayData *od; 924 OverlayData *od;
848 gint id; 925 gint id;
926 gint px, py, pw, ph;
927 GdkWindowAttr attributes;
928 gint attributes_mask;
849 929
850 g_return_val_if_fail(IS_PIXBUF_RENDERER(pr), -1); 930 g_return_val_if_fail(IS_PIXBUF_RENDERER(pr), -1);
851 g_return_val_if_fail(pixbuf != NULL, -1); 931 g_return_val_if_fail(pixbuf != NULL, -1);
852 932
853 id = 1; 933 id = 1;
858 od->pixbuf = pixbuf; 938 od->pixbuf = pixbuf;
859 g_object_ref(G_OBJECT(od->pixbuf)); 939 g_object_ref(G_OBJECT(od->pixbuf));
860 od->x = x; 940 od->x = x;
861 od->y = y; 941 od->y = y;
862 od->relative = relative; 942 od->relative = relative;
863 od->visible = TRUE;
864 od->always = always; 943 od->always = always;
865 944
945 pr_overlay_get_position(pr, od, &px, &py, &pw, &ph);
946
947 attributes.window_type = GDK_WINDOW_CHILD;
948 attributes.wclass = GDK_INPUT_OUTPUT;
949 attributes.width = pw;
950 attributes.height = ph;
951 attributes.event_mask = GDK_EXPOSURE_MASK;
952 attributes_mask = 0;
953
954 od->window = gdk_window_new(GTK_WIDGET(pr)->window, &attributes, attributes_mask);
955 gdk_window_set_user_data (od->window, pr);
956 gdk_window_move(od->window, px, py);
957 gdk_window_show(od->window);
958
866 pr->overlay_list = g_list_append(pr->overlay_list, od); 959 pr->overlay_list = g_list_append(pr->overlay_list, od);
867 960
868 pr_overlay_queue_draw(pr, od, FALSE); 961 pr_overlay_queue_draw(pr, od);
869 962
870 return od->id; 963 return od->id;
871 } 964 }
872 965
873 static void pr_overlay_free(PixbufRenderer *pr, OverlayData *od) 966 static void pr_overlay_free(PixbufRenderer *pr, OverlayData *od)
874 { 967 {
875 pr->overlay_list = g_list_remove(pr->overlay_list, od); 968 pr->overlay_list = g_list_remove(pr->overlay_list, od);
876 969
877 if (od->pixbuf) g_object_unref(G_OBJECT(od->pixbuf)); 970 if (od->pixbuf) g_object_unref(G_OBJECT(od->pixbuf));
971 if (od->window) gdk_window_destroy(od->window);
878 g_free(od); 972 g_free(od);
973
974 if (!pr->overlay_list && pr->overlay_buffer)
975 {
976 g_object_unref(pr->overlay_buffer);
977 pr->overlay_buffer = NULL;
978 }
879 } 979 }
880 980
881 static void pr_overlay_list_clear(PixbufRenderer *pr) 981 static void pr_overlay_list_clear(PixbufRenderer *pr)
882 { 982 {
883 while (pr->overlay_list) 983 while (pr->overlay_list)
898 od = pr_overlay_find(pr, id); 998 od = pr_overlay_find(pr, id);
899 if (!od) return; 999 if (!od) return;
900 1000
901 if (pixbuf) 1001 if (pixbuf)
902 { 1002 {
903 pr_overlay_queue_draw(pr, od, TRUE); 1003 gint px, py, pw, ph;
904 1004
905 g_object_ref(G_OBJECT(pixbuf)); 1005 g_object_ref(G_OBJECT(pixbuf));
906 g_object_unref(G_OBJECT(od->pixbuf)); 1006 g_object_unref(G_OBJECT(od->pixbuf));
907 od->pixbuf = pixbuf; 1007 od->pixbuf = pixbuf;
908 1008
909 od->x = x; 1009 od->x = x;
910 od->y = y; 1010 od->y = y;
911 1011
912 pr_overlay_queue_draw(pr, od, FALSE); 1012 pr_overlay_queue_draw(pr, od);
1013 pr_overlay_get_position(pr, od, &px, &py, &pw, &ph);
1014 gdk_window_move_resize(od->window, px, py, pw, ph);
913 } 1015 }
914 else 1016 else
915 { 1017 {
916 pr_overlay_queue_draw(pr, od, TRUE); 1018 pr_overlay_queue_draw(pr, od);
917 pr_overlay_free(pr, od); 1019 pr_overlay_free(pr, od);
918 } 1020 }
919 } 1021 }
920 1022
921 gint pixbuf_renderer_overlay_get(PixbufRenderer *pr, gint id, GdkPixbuf **pixbuf, gint *x, gint *y) 1023 gint pixbuf_renderer_overlay_get(PixbufRenderer *pr, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1107 0, 0, 1209 0, 0,
1108 pr->window_width, pr->window_height, 1210 pr->window_width, pr->window_height,
1109 &rx, &ry, &rw, &rh)) 1211 &rx, &ry, &rw, &rh))
1110 { 1212 {
1111 gdk_window_clear_area(box->window, rx, ry, rw, rh); 1213 gdk_window_clear_area(box->window, rx, ry, rw, rh);
1112 pr_overlay_draw(pr, rx, ry, rw, rh); 1214 pr_overlay_draw(pr, rx, ry, rw, rh, NULL);
1113 } 1215 }
1114 return; 1216 return;
1115 } 1217 }
1116 1218
1117 if (pr->vis_width < pr->window_width) 1219 if (pr->vis_width < pr->window_width)
1121 0, 0, 1223 0, 0,
1122 pr->x_offset, pr->window_height, 1224 pr->x_offset, pr->window_height,
1123 &rx, &ry, &rw, &rh)) 1225 &rx, &ry, &rw, &rh))
1124 { 1226 {
1125 gdk_window_clear_area(box->window, rx, ry, rw, rh); 1227 gdk_window_clear_area(box->window, rx, ry, rw, rh);
1126 pr_overlay_draw(pr, rx, ry, rw, rh); 1228 pr_overlay_draw(pr, rx, ry, rw, rh, NULL);
1127 } 1229 }
1128 if (pr->window_width - pr->vis_width - pr->x_offset > 0 && 1230 if (pr->window_width - pr->vis_width - pr->x_offset > 0 &&
1129 pr_clip_region(x, y, w, h, 1231 pr_clip_region(x, y, w, h,
1130 pr->x_offset + pr->vis_width, 0, 1232 pr->x_offset + pr->vis_width, 0,
1131 pr->window_width - pr->vis_width - pr->x_offset, pr->window_height, 1233 pr->window_width - pr->vis_width - pr->x_offset, pr->window_height,
1132 &rx, &ry, &rw, &rh)) 1234 &rx, &ry, &rw, &rh))
1133 { 1235 {
1134 gdk_window_clear_area(box->window, rx, ry, rw, rh); 1236 gdk_window_clear_area(box->window, rx, ry, rw, rh);
1135 pr_overlay_draw(pr, rx, ry, rw, rh); 1237 pr_overlay_draw(pr, rx, ry, rw, rh, NULL);
1136 } 1238 }
1137 } 1239 }
1138 if (pr->vis_height < pr->window_height) 1240 if (pr->vis_height < pr->window_height)
1139 { 1241 {
1140 if (pr->y_offset > 0 && 1242 if (pr->y_offset > 0 &&
1142 pr->x_offset, 0, 1244 pr->x_offset, 0,
1143 pr->vis_width, pr->y_offset, 1245 pr->vis_width, pr->y_offset,
1144 &rx, &ry, &rw, &rh)) 1246 &rx, &ry, &rw, &rh))
1145 { 1247 {
1146 gdk_window_clear_area(box->window, rx, ry, rw, rh); 1248 gdk_window_clear_area(box->window, rx, ry, rw, rh);
1147 pr_overlay_draw(pr, rx, ry, rw, rh); 1249 pr_overlay_draw(pr, rx, ry, rw, rh, NULL);
1148 } 1250 }
1149 if (pr->window_height - pr->vis_height - pr->y_offset > 0 && 1251 if (pr->window_height - pr->vis_height - pr->y_offset > 0 &&
1150 pr_clip_region(x, y, w, h, 1252 pr_clip_region(x, y, w, h,
1151 pr->x_offset, pr->y_offset + pr->vis_height, 1253 pr->x_offset, pr->y_offset + pr->vis_height,
1152 pr->vis_width, pr->window_height - pr->vis_height - pr->y_offset, 1254 pr->vis_width, pr->window_height - pr->vis_height - pr->y_offset,
1153 &rx, &ry, &rw, &rh)) 1255 &rx, &ry, &rw, &rh))
1154 { 1256 {
1155 gdk_window_clear_area(box->window, rx, ry, rw, rh); 1257 gdk_window_clear_area(box->window, rx, ry, rw, rh);
1156 pr_overlay_draw(pr, rx, ry, rw, rh); 1258 pr_overlay_draw(pr, rx, ry, rw, rh, NULL);
1157 } 1259 }
1158 } 1260 }
1159 } 1261 }
1160 1262
1161 static void pr_border_clear(PixbufRenderer *pr) 1263 static void pr_border_clear(PixbufRenderer *pr)
2034 2136
2035 if (pr->overlay_list) 2137 if (pr->overlay_list)
2036 { 2138 {
2037 pr_overlay_draw(pr, pr->x_offset + (it->x - pr->x_scroll) + x, 2139 pr_overlay_draw(pr, pr->x_offset + (it->x - pr->x_scroll) + x,
2038 pr->y_offset + (it->y - pr->y_scroll) + y, 2140 pr->y_offset + (it->y - pr->y_scroll) + y,
2039 w, h); 2141 w, h,
2142 it);
2040 } 2143 }
2041 } 2144 }
2042 2145
2043 2146
2044 static gint pr_tile_is_visible(PixbufRenderer *pr, ImageTile *it) 2147 static gint pr_tile_is_visible(PixbufRenderer *pr, ImageTile *it)
2653 } 2756 }
2654 2757
2655 pr_size_clamp(pr); 2758 pr_size_clamp(pr);
2656 pr_scroll_clamp(pr); 2759 pr_scroll_clamp(pr);
2657 2760
2761 pr_overlay_update_sizes(pr);
2762
2658 /* ensure scroller remains visible */ 2763 /* ensure scroller remains visible */
2659 if (pr->scroller_overlay != -1) 2764 if (pr->scroller_overlay != -1)
2660 { 2765 {
2661 gint update = FALSE; 2766 gint update = FALSE;
2662 2767
2742 2847
2743 pr_scroll_clamp(pr); 2848 pr_scroll_clamp(pr);
2744 if (pr->x_scroll == old_x && pr->y_scroll == old_y) return; 2849 if (pr->x_scroll == old_x && pr->y_scroll == old_y) return;
2745 2850
2746 pr_scroll_notify_signal(pr); 2851 pr_scroll_notify_signal(pr);
2747
2748 if (pr->overlay_list)
2749 {
2750 gint new_x, new_y;
2751
2752 new_x = pr->x_scroll;
2753 new_y = pr->y_scroll;
2754 pr->x_scroll = old_x;
2755 pr->y_scroll = old_y;
2756
2757 pr_overlay_queue_all(pr);
2758
2759 pr->x_scroll = new_x;
2760 pr->y_scroll = new_y;
2761 }
2762 2852
2763 x_off = pr->x_scroll - old_x; 2853 x_off = pr->x_scroll - old_x;
2764 y_off = pr->y_scroll - old_y; 2854 y_off = pr->y_scroll - old_y;
2765 2855
2766 w = pr->vis_width - abs(x_off); 2856 w = pr->vis_width - abs(x_off);
3058 box = GTK_WIDGET(pr); 3148 box = GTK_WIDGET(pr);
3059 3149
3060 if (GTK_WIDGET_REALIZED(box)) 3150 if (GTK_WIDGET_REALIZED(box))
3061 { 3151 {
3062 gdk_window_clear(box->window); 3152 gdk_window_clear(box->window);
3063 pr_overlay_draw(pr, 0, 0, pr->window_width, pr->window_height); 3153 pr_overlay_draw(pr, 0, 0, pr->window_width, pr->window_height, NULL);
3064 } 3154 }
3065 3155
3066 pr_update_signal(pr); 3156 pr_update_signal(pr);
3067 3157
3068 return; 3158 return;