qiv-3.0.1/0000775000175000001440000000000014774332463011203 5ustar andyusersqiv-3.0.1/qiv.png0000664000175000001440000005466014774332451012520 0ustar andyusersPNG  IHDR>asRGBbKGD pHYs B4tIME 7*tEXtCommentCreated with The GIMPd%n IDATxYd[߰8'PU.vwp.7-ODOH$$@%!/ j]CXUÙb{"NdVeWz`ikljַ[T_iCD4}3~CDxs~X?x}1?~ǯkOm> ?<0{1~V_4ig?uW}b7z-`,{_;ϑ]0LȈT>[<>\.Q)uߢP,7?_V~1a=GȤiZց|498|+ 8 83JӺ/m ize;!#MM#)4FqƃQ4Agc 2^ٞ ֒e o>ּƘηx+x%g^""6 ڄ#)Oo~)@Rߜi8g +4ཡ%M9)h[FД9a2s퍂,b7XQ}Ltkm[K_q$1mxf, ~41尹lVBdo1nqBȍks¸dӒ6$N+BZ)<8# X3mR!eXL GЩz55qu`ST7Xo/ۗIc= q=ł14] I}4_h8z}~|szYV8t1 )o0.ae FUș72 nYkr>! B >hfbU!%c@NqdBG!Li)afMӡbY,t݌"]/-zfAz+"xWB:M4oA`Ls#b4 qs`lFr;Y 'rΈZ1v$h-1ATlH" rSiXBqJ%5۷#eHIQZu F_2l.|r6x؈0b܄!k@0L0!O"~zql"TPяacDVX ŠYHj0HZ,Y-b(Y{6ÌA\\HO\ukrrf];gvpHcvдKZk16\SšaXTB:|#eU @'R f߇@ f)HxbTR7j5bT jx]u Oq2d9>QrXmXo&۱Y_dqC&~yc^Z[8\b9?c>+36ð:g]4qدDeW'L\:%@ԌP> 8"тR1ѤHkj!o<ĐP {H0a+Z^)ζ4n ϔ ,X:ys&OdWxw rN>n]z׺{{KXϿ:aM64N St<)&iHkِ7' q\RG,МQ+-Iє*X,8:qtOXjdk-$eqB̩G.hd&kLZ"鴤~"$dpw%$X˞' XH×jeoj۶c{<=z>99%42m•9_aEY nδ<'C5$xXk 8i߁ǦyPrR~>RŲ-K%HašP\ (BRR rPZ h0XcoN'9׌Zg! 1l6mJwx8C{nC} bq08Xg1VIb#4C>i.c -0H0(@ndS;Ќ8Bgˌ:< U3yOG͜28K7ٜg; ̄׌#:1%J]%]N57).iOڙVI8rGFb8cRqB0EBN>'oK#YIf=C+eHJ:9Ê)("L2%skEב#np_c^2طg~K$gϽPȰ#pzSZ#tMϸ\wWް8 8@P$̥$0Ix0 1 {Ylo.gȇPj9X@s QԸrJ%\0fE hF a|zs xfyoD!^=q9BG=L]62ރ恔YGN@'4DֈlFX.vJI)ӏBNX%2,=W9Vvx"he Hҟ"K/Z*亮k" FQMs&!(Rk0=Z}kG߁0>3p0'a|!0o3skqkDX@)]6l Z圑\ҽub*k[@6'92kSżFKa,G}Y 8PFќ Yjo jx `䝑 1X!g lҷwO/=XϜX+ {?| k4`!IiEcQHGbj9ZB8弉u}` 9cjN0zWyl|XR4`KVl\Y19)#9c!1 Xd! XBDShg"}Dia!"ӎwa\<3Rܼڼ:OMՏ7?ޝ`5@1:Hy<)9c86 )"1q8JYטU*ȶlkKhĔ~d'"e'm:}S⁜!e$%(EP`5+&jr"8gHtn`Lg -=looB k 4\!3@ ' ư#Vt0 q qĐ1 yx^.fX밶)v뱦0nE ޕlI⎶`6cvc @PT@/ #gR`1tUK@$!FS7kcYri¤%Ʊg9=cu \{̽|=75i4@kȰkÚ* 47>7> lk@FqpNNp>4݇ĩ ebXT56xY 6Kf'ΖP>""eS)Vj &'2RJP;Ir d”PI0k搲B*Y1$$l $Ґ)AyacFLdYb"]g|Oׯ${XGh02p@VVw1r{NO9 &HHKL<)&x+CxkXACb3D l`+WK[Z O\hH.߱o.)f12`m1H'gF@ 8@\c)fY1㒵.Rb5s~]$b7/=% RypiOfCN3`=S&U.޴di.)AM(ѻ5eKaElϱΕx{<#P e q=jɱo;lBV0fRM1}۔[}WV`0ےh4@h1,16AG.s4#"9˻?BnslA 0!1 {,F60 QhXSUe-Kkb"-(1jemMnc-1G]X[ҳ']ֵި"ΗcSERƥBfK*(c( !v[3b. {jWjs9G=lM2Q1c|g/2AP+Ykb^1K;d=F̊sz~igrLuoqs\9𐦉O'w9Cpoij{5K&$ŷ[ˇq+Tݜ+3vH*. {qJ$!4923>ۖg(e߶NTR?+bJ[K1!lJ9oag?RY zNJkNOEϸ9_"+^pT߬mƤ\K~qDƂk Wch"QmATx6c), \bZsi'#q,ˀ{fb&sټ|6#h )x)l!0jeh3'ଭ#SC&?Vf[/61wH+֧w1/x6CĶzdyߒgQ qHig8`04sGJ=YT&r饭nU¡($bPu 5`a|s쌠l'Pbk`3_~ˋ/е37GsnVՀw=]r'\ޕYM0<=cqxyAxG? WKZ]J"pI&a-=s;|)=M{YTFJ u{fmdlu:v 6[fLUTi0 +k<},X¤ݶIͰSE)1KF|*˟Ϝc21'T2SIM5G,8ЉʹmMq2b̈́i qe f.`cͻL5 )K_x_`ژY Xz EiZYg=ĮH$4O(ua191 o=Mr@&raBC$ t[B#3Hʎ;Y*3i&iiaA8A[(BȐypCKm%WizLV%2Bj,2,!8ɑC(}rt){3W)cLf%LJDmn˳ >B7{OÌST7n0 rPfXf+/p˿v瞻L _n̸~L %  9=^xB$)疥vClvaY6'fG_6q_u wO5zaF`)dۂWH < JB`>?ftmiz= ^g.ַO~.UÍ~OWu9?;pwbQcSYUK-M9>r};|pg_=䓟|Hܼzwӯ(` ?(KBm {bv70u::UoFI֭3Xg8 xYϵ+\nl1`vaidUZ W~WhgC IDATo@|OsӸѭ ^qxL.)V="EG] ֘J41ૂg7܏J<1Z<#Zs"@k*4*KSf*McAܖ\qx!yサ,G\o{λg}O~~G ҋ/./0ove-'ÛaoDM{;eynwuc=>ox-~8|ME6TjK%K%4e9ΡW){Rȡ"a)_aLy]8L<&<Փ1ˮe>V"0!* lƁ)Fwtt3o寿}[ڂto 9O~Ҵ |8n[Y4 |i47KFsSAE)F/f׸t/>‹y6OyWxOώX'KʌM{fWP16Tyrji͚)uCF5UٜlRdGƘ+YBCxG[c|泿1 m~%=?q\뱍0?1;X_]C o+QJ [’k/.קzZ|_CHl6#?y}bH^At YbH=[`.DYJPH3Z N9'k1r oo~]._yY/ n٬JHyGTiiWι'ݢ>5nE=+4իZzYի׿$"7{{{}߾4prmf|t %7ׯݻc{o Iv v5+4aS.1/%i.XLӂ67dJRȚ<)IZ4;Q 1+}NXxKV*|dHĎlʧ8J0{ꋎ=DB21"^ H4[#sB.3u |w /zi0<h4sqeM|<[|EkOYm&'^R-2&UmϘ{<.{˦ny胞PP%k̾-t Mc/[ ׋[D.e|;KȲsպzL!1eob9!}?qMu}m[)%'l۷|ʗ.3ܿ|~b栆f$桬tOo/~vWg7};{{ENͥX\=e~-5*^YRf~pX8~F7_feYsE2β5k SOf ڶ''Hʺ>>'/Xmo%3*KRˀ׍T omakժ Ym x5-s;YWCw7'm;a ڶ4MGGvt [@(lgyL, pݯ^yGMlW7\ 懶=U=A⃲ 䢍8ZB,0)}ι]a{'0Ӷb40BveԬgL,k&~냃,믄ȯfԞ!kNjns 3<fOq+Z+wܰ1#Ic=ZJi(q涮s-"+aJId31d1zqWwo a{MWg xGƱuo`k(gEEl7Mv0nmpX%b^!ȭ.Q\hpU}eS+qw,["p5{~er:۶eGf"iW޾= 5Xilw~CUˎ1S'o%Bn,@GM-t*Er5hi Ђ{#8[TEZ1"DUURbPi#Z+8S(H&( ckH|3HEL&鍬 MV${SZŬ/m,#pPw{1]GWJ0o[۔] jq4MmR`,)wYo[ᆭJA|@nkp83<qXU殻v'c%($JX )Mkk?Vc.[/ċI)]^}pZm05m=KXiOii~ /=Ԙlȅi=OEa3 CTXc# D a4}ibVq m3kOi הF#SX#&3d8PY~Oar!C LjL%vHỴ6[P%-f˪=Gs}q(Z}/mOgX§/q;kz= Ca4F9ѷ"lHJtȑ0, )c$G.%5H#lޒsJ#1Me0Iv9F./To P{>پ5m Q2h0/F+9_IbVKȢ.#fU,T"IN;GKW>V*g="h9cfBkB-^FƠ)siBK1i&j1=`QkZ<k]Sb2Tș0Evlt/]D DA+v-k+MTF3T*HS ꡱ5-d mh"ǀ0!uH4j ΎEM<&(jL tU#xifі5` :8ɾk{5LlX%#1;B6P^J̉" Sd R}hRz[Zv95Ќ&srz~9YE,y6lwڙxbqѶ\ b6(zk !V bi+vtuh7(oOXhfm-Kbm`1 )bEz</o۶7ûR ٬k ׽T*m> =S(Ca$9/[;.]Ycu~t?w@w s0i+)%BH{mv%D.R5س"b5h`$a4 %NS9~0Ɓ8NL8N0 00Ne 4%g[fZ'Va.+w,.} oF!sئŷ3nARSn}6G[>TV~hxH{Q| 2$szr?b)7[и{09x:0Ư1B?-K;D 6+MkO_ ᔜS_qH!c1<i+13Ht V/(9 aD!e0)UdDPW1k=kkWiVUňH؎,ʅtR U$u5N(w/0ah5/ wfyMv$Sp̴^azݤ^rjD7ŭSSd9a:%Ieu'NoʩlvD%Ȣl/l؆L%l  ejф?`A Ah%HblǪʬt˞XݔiH)r!87Э[.{"%P38{E(iZ5l CSWU>: ->4l|UL҈4JHgM(b-ѝ=f!iCVȂPHHM0 TUXO_2Up^rrT21['<,;.&֧L`E}+Uh,EIq% `u% "c0b-~Ȗ(2^CK"!x f䥠w;pY{ V6fL+3`J])Bm 454F-CZ/j ج.:qY\^]_ipե^//tn6prp{+ CCI]lR1'3{;d26]F:>RSc-RXl!r # 6 ⃯9_ZW3Vj ٦F#"&Ma(L QЂ0 0I33{Y$M)04&܋Ǽ8%لFQ 6Y:ToƯ%K$Z*^vC&NLt͏}h-4 !|>.!4 Epl@:˟1U:x3%)c^eQAY5ߘ/ !L,X$A {lfa#CbHj0-Kji-‚٤&9=<|u]st焃)븺eC~71YN770 *A\=]WI…-w oy"חxWVO=Sv'*T LBvYzyB39..>PG >[\@"6JGIl5ڥD(c.lM\0@"N ,pD\.({ӢL7h7g? _1sJc#]\ JS-S= , K-*9H gR XԈ̈2m`"ز@4OIjdUEq~tRp83-d^~Bx/еh"D]&ug -!!1!P.hYCu$(jrC¡&ЅL)b m19rIDAT0a}!KNջWt̏rf EzrK AW#ҧ| 6#-LS2Lh5?IBU 6Ɉ 61 T TuF 5bhLѧ΍M[Ö> -uH5LV =e2}1!;Rbf|g !B%M\ 4WuXkb|NSOYb͔|NxT8 !$Q) }'ΡO82fvūPϳ2OMC]ٝ=%}eZS'G%\EL{u7$jgB\ތFQL~E)ngfL"jH41 @m$-2kq{zױZ.&0,݆rՅ21`S'\")3Ɍ0LS$6C$Ț@Cb܄ O 2gݔ0!UZeGrE`.9.df=>}oz-r`LX@Pަr y CrIE(Q=^ҟwLȎ ?ɌzC. ҰhW"X\+wlKX_(n6<~w?5t] ARt}ʥ9v·v6 JK ΈaVcԀH-)mefqm2])95TϾ$FW`<]?@7vg;}>%4vQ2LݣmgMuP{YҦٝ<7v(Ƶt6N F m]svr}ND:~ďǛfe8-&,(z춆` j?&K_MnU(1Ɩx5K FGa L&wj:fI?JgCHGAIaͩ[!Jl!I"l;I vKcכ"gv gthGgO_9< g# xD RO1C&X$ZrODL|jkXdeASF֫k{ȽW?Q_(UC\R73&SǦ1ds<9|]3VRе.٩[i*b1fϯ2iXfYғ*e ]g"F 5 ]ɝ[*Ce4?&hJ&\ Е>7MrCƛ.F^p{#| i( DuKPNsӨ"[vn$!FAQ>bKKe \4tgtp`'ִmdBZGMY UbQniߝUwuwq1IGTOi 6e'R8M(&Slkİ"iJQr6|؎MB­"0jv[@lh,}~V Ɉb'ϟWH$0Moטױ,00eպl`^l1LVWSϨ ԧ/=\mM;:ey~N5JeZ L/ɢR3c bz3"c=ҏq<}ҽC"k9/Q#f\zd󈐚^eTClmdP GwY.X{fP쟈b( F Ҽ*~óخ 9_PULM3y3hv`FAu/@zm/hɬTT䃸ԕ<o60;17قNʝ>o&9805uPih▾r䂗^Kmj4n;My~o~.oUGw9['/tq ~ig ńT1P3O!nXECsNEPn\o-?]Genpevnt"{,r89{8E2!IclaH_KitBwB;0-Xh%O8=T@e_UnЬl6EjyM()Nc& pm MIKȐ.`QO!1#(jB2 ~LNwEq_P! YidF ,rSxB4!fBHI)[mP:/ ^PyTOh]ĉEʆo|R>RSE7/Pnmt'/~Nu %R*ug|ˆ@PN(-WiIA΃-"*DJP8[PN1.ځ}~}M~A\]SK,29dyk8LT %`$`mWfGj@q 95ܳDM0mOqDY#B7Q2ZGvqm0[lJ-a BJ6iBj ,Ռ509| ੌ=hxZ٫Hq|7^]YEYUpV(p1wO>G"&_?7`1ˇ\?T!ْdIi'\>Q9)WrN(*$0b3IRBqQӌ[I O>Svm+͜(9*G=7 1#, X@ v48,+Ѱ TSݘ| |U_}YG:-۾reva8arxȏz;|ZbvW ( Zل:v *d (tm&#'S| IN#e8(YQ+H4  7 E+(s(IW:(.F*P l1dž>vڞhʀ}.8AuX{`ixsy'o^Qk˓\חtt,1!pPOp&eUUQ76XIo @YL2. &%!dZm)oA5YPR <6`ZU̚w@up( g-g-/ַzy.ޢo7LՕ2z;=eC:h3n0I!Q!{`菻f`=*C^Er@saP-1Z?Pa~~SJcb sV\Y}1cq 4w_Qql}H_eOϩ?vR~"4ԗ\jחױl7!RU٤45d]Y) JSqP#ðIp!}H҅x{B n IuC&rAE&G Iw&iKآ3h[Zp|<)>kQ^ZgWY_i7-Vﳹ'?`uzʤc4!nfKmиN!ӘV!C Am|L,#$)1fKz Zr0j RM7c x&@RZCS>J8}/2_d㔿+- wIEλ?˞_/zŷk'CKNE?b&k< c( 9eYҶM(,EMSMLL &dJa+t)JjJY4dT"T8ӳf[=Rf<~ðF]ҮW^y<M%1t,*O]1  锢0CKns#s~M4Þid.n0|s>5o]ӗۃM&f+LtWLp1`Q ,ry.ɍSȵ)ҍ6b'\iEuTL^)݀ )jL_MѼ 4حEQ\8v4M1|[pk>4[n^7D^x8?5+yla(„1 `L ^(FInQYe!LQᆴ(\޽%~]wwCaQ.9ۛ5k-u]l6fa?g_%7kɔd<^IENDB`qiv-3.0.1/main.c0000664000175000001440000002141114774332451012267 0ustar andyusers/* Module : main.c Purpose : GDK/Imlib Quick Image Viewer (qiv) More : see qiv README Homepage : http://qiv.spiegl.de/ Original : http://www.klografx.net/qiv/ Policy : GNU GPL */ #define _DEFAULT_SOURCE #include #include #include #include #include #include #ifdef HAVE_MAGIC #include #endif #include "qiv.h" #include "main.h" qiv_image main_img; qiv_mgl magnify_img; /* [lc] */ static int check_extension(const char *); static void qiv_signal_usr(int sig); static gboolean qiv_handle_timer(gpointer); static void qiv_timer_restart(gpointer); #ifdef HAVE_MAGIC static int check_magic(magic_t cookie, const char *name); #endif int main(int argc, char **argv) { struct timeval tv; int i; // [as] workaround for problem with X composite extension // is this still needed with imlib2 ?? putenv("XLIB_SKIP_ARGB_VISUALS=1"); /* // [as] thinks that this is not portable enough // [lc] // I use a virtual screen of 1600x1200, and the resolution is 1024x768, // so I changed how screen_[x,y] is obtained; it seems that gtk 1.2 // cannot give the geometry of viewport, so I borrowed from the source of // xvidtune the code for calling XF86VidModeGetModeLine, this requires // the linking option -lXxf86vm. XF86VidModeModeLine modeline; int dot_clock; */ /* Randomize seed for 'true' random */ gettimeofday(&tv,NULL); srand(tv.tv_usec*1000000+tv.tv_sec); /* Initialize GDK */ int has_display = gdk_init_check(&argc,&argv); /* Set up our options, image list, etc */ strncpy(select_dir, SELECT_DIR, sizeof select_dir); reset_mod(&main_img); options_read(argc, argv, &main_img); if (!images) { /* No images to display */ g_print("qiv: cannot load any images.\n"); usage(argv[0],1); } if (!has_display) { /* No DISPLAY */ g_print("qiv: DISPLAY not set.\n"); usage(argv[0],1); } #ifdef SUPPORT_LCMS /* read profiles if provided */ if (cms_transform) { if (source_profile) { h_source_profile = cmsOpenProfileFromFile(source_profile, "r"); } else { h_source_profile = cmsCreate_sRGBProfile(); } if (h_source_profile == NULL) { g_print("qiv: cannot create source color profile.\n"); usage(argv[0],1); } if (display_profile) { h_display_profile = cmsOpenProfileFromFile(display_profile, "r"); } else { h_display_profile = cmsCreate_sRGBProfile(); } if (h_display_profile == NULL) { g_print("qiv: cannot create display color profile.\n"); usage(argv[0],1); } } /* TYPE_BGRA_8 or TYPE_ARGB_8 depending on endianess */ h_cms_transform = cmsCreateTransform(h_source_profile, #if G_BYTE_ORDER == G_LITTLE_ENDIAN TYPE_BGRA_8, h_display_profile, TYPE_BGRA_8, #else TYPE_ARGB_8, h_display_profile, TYPE_ARGB_8, #endif INTENT_PERCEPTUAL, 0); #endif /* Load things from GDK/Imlib */ qiv_main_loop = g_main_loop_new(NULL, TRUE); screen_x = gdk_screen_width(); screen_y = gdk_screen_height(); screen = gdk_screen_get_default(); num_monitors = gdk_screen_get_n_monitors(screen); monitor = malloc( num_monitors * sizeof(GdkRectangle)); for(i=0; i< num_monitors ; i++) { gdk_screen_get_monitor_geometry(screen, i, &monitor[i]); } if(user_screen < num_monitors) { main_img.mon_id = user_screen; } /* statusbar with pango */ layout = pango_layout_new(gdk_pango_context_get()); fontdesc = pango_font_description_from_string (STATUSBAR_FONT); /* set default fontsize if no fontsize is given */ if(!pango_font_description_get_size(fontdesc)) { pango_font_description_set_size(fontdesc, PANGO_SCALE * STATUSBAR_FS); } pango_font_description_set_size(fontdesc, pango_font_description_get_size(fontdesc) * highDPIfactor); metrics = pango_context_get_metrics (gdk_pango_context_get(), fontdesc, NULL); pango_layout_set_font_description (layout, fontdesc); /* jpeg comment with pango */ layoutComment = pango_layout_new(gdk_pango_context_get()); fontdescComment = pango_font_description_from_string (COMMENT_FONT); /* set default fontsize if no fontsize is given */ if(!pango_font_description_get_size(fontdescComment)) { pango_font_description_set_size(fontdescComment, PANGO_SCALE * COMMENT_FS); } pango_font_description_set_size(fontdescComment, pango_font_description_get_size(fontdescComment) * highDPIfactor); metricsComment = pango_context_get_metrics (gdk_pango_context_get(), fontdescComment, NULL); pango_layout_set_font_description (layoutComment, fontdescComment); /* show artist name with pango */ layoutArtist = pango_layout_new(gdk_pango_context_get()); fontdescArtist = pango_font_description_from_string (ARTIST_FONT); /* set default fontsize if no fontsize is given */ if(!pango_font_description_get_size(fontdescArtist)) { pango_font_description_set_size(fontdescArtist, PANGO_SCALE * ARTIST_FS); } pango_font_description_set_size(fontdescArtist, pango_font_description_get_size(fontdescArtist) * highDPIfactor); metricsArtist = pango_context_get_metrics (gdk_pango_context_get(), fontdescArtist, NULL); pango_layout_set_font_description (layoutArtist, fontdescArtist); max_rand_num = images; /* Display first image first, except in random mode */ if (random_order) next_image(0); //disabled because 'params' is never used, see above //if (to_root || to_root_t || to_root_s) { // params.flags |= PARAMS_VISUALID; // (GdkVisual*)params.visualid = gdk_window_get_visual(GDK_ROOT_PARENT()); //} /* Setup callbacks */ gdk_event_handler_set(qiv_handle_event, &main_img, NULL); qiv_timer_restart(NULL); /* And signal catchers */ signal(SIGTERM, finish); signal(SIGINT, finish); signal(SIGUSR1, qiv_signal_usr); signal(SIGUSR2, qiv_signal_usr); /* check for DPMS capability and disable it if slideshow was started from command options */ dpms_check(); if(slide){ dpms_disable(); } /* Load & display the first image */ qiv_load_image(&main_img); if(watch_file){ g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 100, qiv_watch_file, &main_img, NULL); } g_main_loop_run(qiv_main_loop); /* will never return */ return 0; } void qiv_exit(int code) { destroy_image(&main_img); dpms_enable(); pango_font_description_free (fontdesc); g_object_unref (layout); pango_font_metrics_unref(metrics); g_main_loop_unref(qiv_main_loop); finish(SIGTERM); /* deprecated, subject to change */ } /* * function for handling signals (only USR1 and USR2 handled) */ static void qiv_signal_usr(int sig) { if (sig == SIGUSR1) { next_image(1); } else { next_image(-1); } qiv_load_image(&main_img); } /* * Slideshow timer function * * If this function returns false, the timer is destroyed * and qiv_timer_restart() is automatically called, which * then starts the timer again. Thus images which takes some * time to load will still be displayed for "delay" seconds. */ static gboolean qiv_handle_timer(gpointer data) { if (*(int *)data || slide) { next_image(0); /* disable screensaver during slideshow */ XResetScreenSaver(gdk_x11_display_get_xdisplay(gdk_display_get_default())); qiv_load_image(&main_img); } return FALSE; } /* * Slideshow timer (re)start function */ static void qiv_timer_restart(gpointer dummy) { g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, delay, qiv_handle_timer, &slide, qiv_timer_restart); } /* Filter images by extension */ void filter_images(int *images, char **image_names) { int i = 0; #ifdef HAVE_MAGIC magic_t cookie; cookie = magic_open(MAGIC_SYMLINK); magic_load(cookie,NULL); #endif while(i < *images) { if (check_extension(image_names[i]) #ifdef HAVE_MAGIC || check_magic(cookie, image_names[i]) #endif ) { i++; } else { int j = i; if (j < *images-1) image_idx--; while(j < *images-1) { image_names[j] = image_names[j+1]; ++j; } --(*images); } } #ifdef HAVE_MAGIC magic_close(cookie); #endif if (image_idx < 0) image_idx = 0; } static int check_extension(const char *name) { char *extn = strrchr(name, '.'); int i; if (extn) for (i=0; image_extensions[i]; i++) if (strcasecmp(extn, image_extensions[i]) == 0) return 1; return 0; } #ifdef HAVE_MAGIC static int check_magic(magic_t cookie, const char *name) { const char *description=NULL; int i; int ret=0; description = magic_file(cookie, name); if(description) { for(i=0; image_magic[i]; i++ ) if (strncasecmp(description, image_magic[i], strlen(image_magic[i])) == 0) { ret = 1; break; } } return ret; } #endif qiv-3.0.1/Changelog0000664000175000001440000012647314774332451013027 0ustar andyusersAuthors: ak: Adam Kopacz as: Andy Spiegl de: Darren Smith pa: Pavel Andreev df: Decklin Foster hm: Holger Mueller ss: Scott Sams sw: Serge Winitzki fc: Frederic Crozat rn: Rutger Nijlunsing jk: John Knottenbelt da: Danny to: Tomas Ogren ej: Erik Jacobsen aw: Alfred Weyers da: Daniel hk: Henning Kulander ab: Ask Bjoern Hansen al: Adrian Lopez yf: Y Furuhashi wd: Wayne Davison js: Johannes Stezenbach ok: OEyvind Kolaas mc: Matthieu Castet jd: Geoffrey T. Dairik lc: Leopoldo Cerbaro hl: Heikki Lehvaslaiho ld: Larry Doolittle sd: S. Dobrev tw: Thomas Wiegner bd: Barry deFreese pw: Peter deWachter ap: Akos Pasztory 3.0.1 ======== 03.04.2025 [tw] Fix compilation problem with newer gdk3 versions (fixes issue #2, patch by arenevier) 3.0.0 ======== 31.03.2025 [tw] Migration to GDK3. 2.9.0 ======== 17.03.2025 [tw] Intermediate version. Remove imlib2, use gdk2/gdkpixbuf for image handling. 2.3.4 ======== 19.02.2025 [tw] minor cleanup and gcc-15 fixes (debian #1097695) 03.02.2025 [tw] add heic and webp entries to desktop and mime file 06.08.2023 [tw] Correct libwmf-gtk recommends, remove "-l" from desktop file, increase debhelper compat level to 7 14.04.2023 [tw] fix possible segfault on corrupt color profiles (Gabriel Vlasiu) 2.3.3 ===== 28.01.2023 [as] qiv-command example: added more interesting tags in exiftool.tags.for.qiv-command 28.01.2023 [as] qiv-command example: added gps2url and gimp 23.01.2023 [tw] allow --help and --version without DISPLAY variable set 23.01.2023 [tw] scale fonts according to highDPIfactor 23.01.2023 [tw] fix some deprecation warnings 15.01.2023 [as] fix small bug with --highDPIfactor and --scale_down and images smaller than screen size before enlarging but bigger than screensaver after enlarging 22.11.2022 [as] new cmdline option --highDPIfactor: zoom factor to compensate for high (or also low) DPI screens 22.11.2022 [as] statusline+window title: move not so interesting loading time to the end 22.11.2022 [as] fix removing artist/comment text in fullscreen mode 13.11.2022 [as] add ability (and options and toggles) to display EXIF artist name 14.12.2021 [tw] add heif image support via gdk-pixbuf loader add example in qiv-command on how to run programs without blocking qiv 17.07.2021 [tw] add webp support via imlib loader (Ralf Hoffmann) 27.11.2020 [tw] fix wrong man path, fix clang-10 compiler warning, include debian #969338 09.09.2020 [as] zoom in faster (+50% instead of +10%) if above 100% 09.09.2020 [as] redefined GDK_SCROLL events to move image in fullscreen 30.08.2020 [tw] replace deprecated gdk_draw functions with cairo functions 15.07.2018 [tw] fix: don't ignore maxaspect and scale down options when reloading image due to watch option on. (Issue #8) 2.3.2 ===== 31.10.2017 [tw] fix: window sometimes recentered, when moved around with mouse 19.10.2017 [as] fix Makefile for cross-compiling: Make pkg-config substitutable (Debian Bug#879108) 10.10.2017 [tw] add specfile to build rpm for CentOS 07.10.2017 [tw] add option --trashbin to use trash bin instead of .qiv-trash when deleting images 06.10.2017 [as] add ability (and options) to display JPEG comments 06.10.2017 [as] more sophisticated exiftool call in qiv-command example 04.10.2017 [tw] fix inconsistent fixed-zoom behaviour 10.08.2017 [tw] Don't try to rotate if file is not an image 06.06.2017 [tw] get rid of some more XID collisions 30.05.2016 [tw] Fix occasionally erratic behaviour of qiv statusbar [tw] Fix xpm autodetection with libmagic 26.05.2016 [tw] Fix small artefacts in pictures which might happen when running remote over slow link (patch by Derek Schrock) 20.05.2016 [tw] update image after it is exposed in window mode 12.05.2016 [js/tw] fix broken "-no-filter" option libmagic filter now works on symlinks 07.11.2015 [tw] fix linking order in "make debug", did not work in some newer gcc versions 18.06.2015 [as] turn on EXIF autorotation by default 13.09.2014 [tw] Add option to sort files by modification time. (patch by Stefan Rüger) 23.04.2014 [tw] In case of "watch" option, check image only every 1/10 sec, instead of every 200us. This was way too short for devices like RasPi etc. (Hamish) [tw] Leave jumping mode on invalid input and process input key as if it was entered in non jumping mode (Sergey Pinaev) 2.3.1 ===== 25.11.2013 [tw] Add libXext to libraries for linking in Makefile. Fixes build problems on some distributions. 2.3 ===== 23.09.2013 [as] unicode fix for gps2url.py 22.09.2013 [tw] Some cleanup in the debian subdir 19.03.2013 [tw] Add desktop integration. Add gps2url.py script. 18.03.2013 [tw] browse option now starts with first picture on command line. [tw] fix direction of scrollwheel for next/previous image 25.02.2013 [as] center mouse cursor position in magnifying window [tw] external script gps2url.py to extract GPS coordinates from an image and call firefox with google maps url if the GPS info exists [as] integration into qiv-command.example 19.02.2013 [tw] update COPYING and optimize libmagic calls Patch by Jiri Slaby 05.02.2013 [tw] improve display of exif GPS tags 01.02.2013 [as] new option --vikeys to allow for vi-style movement Suggested/Patch by anonymous contributor 13.01.2013 [tw] disable screensaver and DPMS during slideshow 30.11.2012 [as] improvements to qiv-command.example (filename quoting, extract more EXIF infos) 22.09.2012 [tw] fix possible segfaults when dealing with corrupt embedded color profiles. 12.03.2012 [tw] do not segfault when "browse" option is called without a further argument. 28.01.2012 [tw] fix magnifying window. Zoom factor of magnifying window can be changed by +/- keys. 22.01.2012 [tw] fix missing #ifdef HAVE_EXIF for exif header file (Herbert J. Skuhra) 21.01.2012 [tw] get rid of XID collision [tw] code cleanup, mostly exif 07.01.2012 [wd] Make conditional rotate leave images that fit alone. [wd] Add --followlinks option to all symlinks to dirs. [wd] Fixed inconsistency with rotate option, add conditional rotation 06.01.2012 [tw] Add runtime option to display Exif information 12.12.2011 [tw] Add runtime option to toggle grab mode 09.12.2011 [tw] Add support for embedded color profiles in tiff 02.12.2011 [tw] Better fullscreen handling with multi monitors. Xinerama is no longer needed. 30.10.2011 [wd] Notice when a mouse click makes the display-text disappear. [wd] Center display-text on the preferred xinerama screen. [wd] Simplify image-move checking code and allow it to move an image farther. 22.10.2011 [tw] Replace GDK_ with GDK_KEY_ 16.10.2011 [tw] Add support for embedded color profiles in jpg 12.10.2011 [tw] replace gdk_window_set_icon with gdk_window_set_icon_list. [tw] add color profile support via lcms2. (patch by Hans Philipp Annen) 19.07.2011 [tw] when using "--watch" option, make sure pic is not reloaded while still written. 2.2.4 ===== 02.05.2011 [as] README: added note about obsoleted GTK v1 28.12.2010 [as] qiv-command: more examples from Clint Pachl 02.11.2010 [tw] only center image upon reload when center option is active [tw] Do not break install if using a non existing target location (clemens fischer) [tw] make gdk options work again (e.g. --display) [tw] Do not follow symlinked directories, when using recursivedir option (Goswin v. Brederlow) [tw] Add option to change cycle behavior after last picture. (patch by Nicolas Pouillard) [tw] Images were displayed twice when using --browse option. (patch by Adam Lee) [tw] Fix inconsistent behavior when using -x/-y/-z option. 2.2.3 ===== 10.01.2010 [tw] add 'Q' icon in qiv-window [tw] bring back scrollwheel functionality (Based upon a patch sent by "Johnny") Zoom in/out with left/right scroll and forward/back buttons [tw] change loading of images from imlib2_loader to pixbuf_loader. Adds support for additional file types, e.g. pcx, ico, svg, wmf and better handling of transparency. [tw] use gdk_pixbuf to autorotate with EXIF tags instead of libexif. Note: needs at least GDK 2.12 [tw] Resetting the image (pressing return) no longer destroys "transparency checkboard" [tw] Fix compilation issues with unusual linker defaults. Update solaris Makefile. [tw] new option to start with default rotation (patch submitted by Atsushi Kamoshida) 2.2.2 ===== 30.05.2009 [tw] fix -x (root window needs colormap) [tw] patch pango code to avoid garbled output of F1 [as] fix wrong image size after autorotating 2.2.1 ===== 28.05.2009 [tw] recognize changed files, using --slideshow and --watch [tw] sanitize infotextdisplay [tw] check EXIF tags only after successful file loading [tw] shuffle now implies not to sort filenames [tw] fix autorotate with EXIF-tag [tw] avoid crash calling qiv -x without argument [ap] fix behaviour of "recursivedir" switch [as] added note in README and qiv.h explaining a problem of includes with imlib2 up to v1.2 [as] migrated notes in README from imlib1 to imlib2 [tw] migrated gdk_draw_text() to gdk_draw_layout() fixing wrong display of utf-8 filenames 2.2 === 30.04.2009 [pw] migration from imlib1 to imlib2 2.1 === 05.03.2009 [as] Adam Kopacz delegated to new maintainer: Andy Spiegl [as] new homepage: http://qiv.spiegl.de/ [as] removed obsoleted GDK_WA_WMCLASS see http://library.gnome.org/devel/gdk/2.11/gdk-Windows.html#GdkWindowAttr and http://developer.gimp.org/api/2.0/gtk/GtkWindow.html#gtk-window-set-wmclass Thanks to Bernhard Kaindl . [as] added patch from Debian gtk_includes.diff, closes: #456854 [as] added patch from Debian cmdbuflen.diff, closes: #441401 Thanks to Norman Ramsey . [as] added patch from Debian man_xscreensaver.diff [as] remove xscreensaver left overs from Makefiles [sd] added autorotate patch (using libexif) by sdobrev@sistechnology.com [as] display initial autorotation in status bar, option "autorotate" [tw] patch to detect image types using libmagic [de] added GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK in image.c [de] removed TGA and XBM because not supported by imlib anymore [de] exit on unmapped mouse events [de] browse option -B, useful when launching qiv from a file manager 21.05.2007 [pre13] [ld] patch to prevent segfault on amd64 02.05.2007 [pre12] [as] avoid wrapper, include "XLIB_SKIP_ARGB_VISUALS=1" in main.c 25.04.2007 [as] include README and README.TODO in debian package README.TODO: fvwm style setting has to be for "therealqiv" 25.04.2007 [pre11] [as] include Debian changes and package files: renamed README.CHANGES to Changelog added patch hide_therealqiv (for Debian Bug #326849) added patch xmalloc (Debian Bug #383113) added patch qiv-manpage-options (Debian Bug #383108) don't recurse directories given on command line (better: use -u) NOT added: no_background_opts (can't reproduce Debian Bug #351816) added patch qiv-nosort [hl] patch to reset bright/contrast/gamma hitting "o" (2006-06-29) 24.04.2007 [as] more comments and examples in qiv-command option -X to set preferred xinerama screen key "X" cycles through available xinerama screens after 'X' window moves to the new screen right away prefix "^" instead "0" for extended call of qiv-command workaround-patch by Bart Martens for problem with X composite extension try keep image on the screen after zooming/rotating fixed centering=off behaviour in fullscreen mode fixed "magnifying glass" windowsize bug fixed compiler warnings "differ in signedness" fixed compiler warning "missing sentinel in function call" 07.10.2005 [lc] bugfix: statusbar is redrawn after size changes and moves 30.09.2005 [lc] "magnifying glass" patch (not perfect yet) call of qiv-command with "0"-prefixed option 10.05.2005 [pre10] [AK] Added Patch by Christoph Wegscheider (new QIV Debian maintainer). Now all free Keys can be used by qiv-command 27.03.2005 [pre9] [jd] Another Xinerama bugfix (statusbar: now displayed on the smaller screen if two are used) 23.02.2005 [pre8] [as] new qiv-command feature: if first output line is like "NEWNAME=xxxxxxx" then qiv understands that the filename of the currently displayed image has changed to this new name (very useful when using qiv-command to rename files) fix image position when zooming to avoid wild jumps delete files from list if they cannot be loaded display text popup after qiv-command not only in fullscreen mode qiv_display_text_window: adjust minimum width of box after qiv-command also check file size and ctime avoid file overwrites in .qiv-select (NEEDS IMPROVING) updated and added more examples to qiv-command 01.01.2005 [pre7] [ak] added small patch by Nick Clifton : setting WM_CLASS name to "qiv" (attr.wmclass_name). 05.12.2004 [pre6] [ak] changed a-key/copy to real copy (no links anymore) 11.09.2004 [pre5] [ak] patch-bugfix by Christian Lademann 01.09.2004 [pre4] [ak] adden patch by Christian Lademann now slideshow (-s) can also be combine with -x/y/z 07.07.2004 [pre3] [ak] added -F Patch by Martin Fiedler now stdin can also be used.. 16.06.2004 [pre2] [jd] Xinerama bugfix 26.05.2004 [pre1] [wd] small changes in delete-command 2.0 === 22.05.04 [ak] released v2.0! 08.05.04 [pre12] [ak] some Makefile.Solaris changes again Work-Tests: Soalis=ok, FreeBSD (5.2-CURRENT): ok 07.05.04 [pre11] [ak] changed round(); to myround(); and fixed Makefile.Solaris 24.04.04 [pre10] [jk] fixed qiv_display_text_window 24.04.04 [pre9] [ak] added patch by Joachim Kuebart (kuebart@mathematik.uni-ulm.de) if images is < 5 and PgUp is pressed, image_index might become negative.. [mc] small patch that remove a warning with gcc 3.4 19.04.04 [pre8] [jk] qiv_display_text_window update (Push any key..) - its really cool! :-) [ak] cleaned up README, qiv-command.example, manpage.. 19.04.04 [pre7] [jk] Fixed Help-Screen remove. Added qiv-command-stdout support, now "metacam" (EXIF-Header) or other tools can be used within qiv and the output is shown in a box in the pixture like the helpscreen. 18.04.04 [pre6] [ak] All arrow-keys = normal moving. All arrow-keys+Shift = faster moving. NumPad-arrow-keys+NumLock = faster moving. 18.04.04 [pre6] [ak] All arrow-keys = normal moving. All arrow-keys+Shift = faster moving. NumPad-arrow-keys+NumLock = faster moving. 18.04.04 [pre5] [mc/ak] Added patch: Faster moving of pictures with pushed Shift+Arrow-Keys. 14.04.04 [pre3/4] [jd] Xinerama patch (MultiHead XFree86 V. 4.0+) 23.02.04 [pre2] [ak] fixed manpage (ignore_path_sort was wrong) 08.01.04 [pre1] [ak] Added patch by HaJo Schatz (hajo@hajo.net): "--disable_grab, -G" Disable pointer/kbd grab in fullscreen mode for Remote-Display stuff. 1.9 === 13.12.03 [-----] [ak] Cleaned up version-stuff and released 1.9 :-) 10.11.03 [pre19] [ok] added patch: capability to watch a file for changes, --watch/-T options 27.09.03 [pre18] [ak] removed qiv_set_cursor_timeout from fullscreen-key-event. It hangs with FVWM2. 27.09.03 [pre18] [js] added patch: capability to drag the image with the mouse in fullscreen mode and fixed bugs related to background repainting with --bg_color 23.09.03 [pre17] [ak] added patch by Johannes Stezenbach which hides the mouse cursor after one second and redisplays it when the mouse is moved. I also cleaned up bugs with the delay adjustments (F11/F12), and made sure the 'q' key comes through even when starting with delay 0. 13.09.03 [pre16] [ak] added patch / undelete (link) replaced by rename. Now also works on FAT. 09.09.03 [pre15] [ak] added patch / delete (link) replaced by rename. Now also works on FAT. http://bugs.debian.org/209079 16.06.03 [pre14] [ak] added patch by Robert R. Pavlis fixed event queues (KeyComands). Now a key can be hold down for a while ;) 25.05.03 [pre13] [ak] added patch by Martin Pitt / DEBIAN Fixed handling of non existing images (no crash anymore) 24.05.03 [pre12] [ak] added patch by Martin Pitt / DEBIAN Now -d can contain 0.5 seconds or so.. 16.02.03 [pre11] [ak] added patch by Drew Cohan Key F11/F12 now in-/decrease the Slideshow-Delay (+/- 1 sec). Think its maybe time for QIV v2.0 ?! :-) 13.01.03 [pre10] [ak] added patch by J'raxis 270145 --file= (-F) option to qiv to allow it to read image/directory names from a text file 24.12.02 [pre9] [ak] added PBM support (just the extension) 20.10.02 [pre8] [ak] added patch by Wayne Davison scale-down rotation quirk. 20.10.02 [pre7] [ak] added patch by Kim Rasmussen fixed WM "wmx v6" centering problem. 04.10.02 [pre6] [ak] added patch by Lin Zhemin A-key to copy images to "./.qiv-select". 26.09.02 [pre5] [ak] added patch by Wayne Davison (some small changes) 11.09.02 [pre4] [ak] added patch by Geoff Richards great patch to reduce flicker while moving in fullscreen :-) 26.08.02 [pre3] [ak] added patch by Simon Budig removed "-u". qiv is now detecting directorys. added "-R" (readonly option). 10.08.02 [ak] added jpeg ".jpe" support (just the extension). 05.08.02 [pre2] [ak] added patch by Qef Richards : changed the option handling slightly so that invalid arguments to options which want numbers will be detected and a suitable error message printed. 20.07.02 [pre1] [ak] now using qiv_load_image after qiv-command (no segfaults anymore) 1.8 === 16.07.02 [----] [ak] Released 1.8 :-) 07.07.02 [pre8] [ak] added zoom in/out bugfix from Qef Richards 29.06.02 [pre7] [as] fixed load_time. now the real render/load/display-time is displayed. 09.06.02 [pre6] [as] fixed image moving merged update_m_image and update_z_image into update_image 05.06.02 [pre5] [as] fixed trashdir and delete path, fixed rounding error of zoom factor in statusbar added support for transparency in fullscreen mode (leaves a problem with the disappearing window border) added a Transparency toggle added possibility for the statusbar in non-fullscreen mode added command line switch "I" to force display of the statusbar changed command line switch ignore_path_sort from "I" to "P" added command line switch "W" for a fixed zoom factor added a Center mode toggle changed meaning of page down/up keys 16.05.02 [pre4] [ak] Added reload-after-qiv-command-patch from "Andy Spiegl " 12.05.02 [pre3] [ak] Added Iconify-Patch (Key: I) from "Goetz Waschk " 29.12.01 [pre2] [ak] Added manpage-patch (qiv-command changes) from James M Corey 31.07.01 [pre1] [ak] added patch from Matthias Kilian (adds random order when starting qiv in shuffle mode & fixed deleting and undeleting a picture which is a symlink) 1.7 === 05.07.01 [----] [ak] added a qiv-command.example & released 1.7 :-) 10.06.01 [pre9] [ak] added qiv_command_patch from post@volker-wysk.de 03.06.01 [pre8] [ak] image_moving now uses func update_m_image. no screen clean first anymore -> faster moving :) zoom now uses update_z_image -> a little bit faster zoom (+0.1s?) added README.TODO 11.05.01 [pre7] [wd] Fixed window-resizing in non-fullscreen mode. Fixed combining -x with -m or -t. 02.05.01 [pre6] [wd] Fixed mouse-hiding on button-push when fullscreen. Added some missing names to the doc file. 30.04.01 [pre5] [wd] Hide the mouse on keypress and button push when it is in the qiv window (the mouse is re-shown on mouse movement). Improved the sort algorithms (particularly the numeric sort). 02.04.01 [pre4] [wd] rreaddir() patch. 28.03.01 [pre3] [wd] Added undelete image command (bound to u & U). Allow the user to specify multiple -u options and also to specify files on the commandline in addition to -uDIRs. Added new commandline sorting options (-I, -M, & -N). Optimized rreaddir(), next_image(), and get_random(). Improved the implementation of shuffle. Other misc. (and minor) bug fixes and tweaks. 20.02.01 [pre2] [yf] removed slideshow_exit from default event. 17.02.01 [pre1] [yf] added the option -w x or --width x for displaying with a fixed window-width. 1.6 === 18.01.01 [1.6] [ak] killed "pre8" string, -v (gzip) - we dont neet verbose mode *g* release qiv 1.6 06.01.01 [1.6] [df] Put 'm' back in help text (oops!) 06.01.01 [pre8] [df] Rewrote part of the extension filtering code. 06.01.01 [pre8] [df] Move the program used to compress man pages (gzip -9vf) up to the top so that it can be disabled easily. 06.01.01 [pre8] [df] Some HP-UX compilation fixes. 05.01.01 [pre7] [df] Change zoom_in/zoom_out so that they will break out of maxpect/scale_down mode, and make maxpect/scale_down override each other. 05.01.01 [pre7] [df] A whole bunch of other cleanups. 05.01.01 [pre7] [df] Updated keys help text for rotation/moving. 05.01.01 [pre7] [df] Fixed bug that caused the image not to update when brightness/contrast/gamma was re-adjusted to 0/0/0 (with either the Enter key or B/C/G.) 05.01.01 [pre7] [df] Merged README.SPEED_UP into README. 05.01.01 [pre7] [df] Don't reset image size when rotating, and scale properly according to maxpect/scale_down. 05.01.01 [pre7] [df] Fold filter.c into main.c. 05.01.01 [pre7] [df] Big cleanup: move everything pertaining to the image into a qiv_image struct and pass that as an argument to most functions. Got rid of a lot of global variables. 04.01.01 [pre6] [df] gzip manpage with -9 (This is required for Debian packages, and is a good idea anywhere). 04.01.01 [pre6] [df] Replace strcpy/strcat with strncpy/snprintf in rreaddir and move2trash to prevent a few more possible overflows. 04.01.01 [pre6] [df] Clean up initialization code. 04.01.01 [pre6] [df] Redo color handling: remove GDK deprecated functions and internal color list. Now you can use any color from X's rgb.txt or equivalent (however, you may have to change '123456' to '#123456'). 03.01.01 [pre5] [df] Fix Makefile to handle fonts with spaces in their names. 03.01.01 [pre5] [df] Use actual font height when drawing the help screen and statusbar instead of hardcoding it. 03.01.01 [pre5] [df] Plug text_font and statusbar_background_gc memory leaks. 03.01.01 [pre5] [df] Use helpstrs in show_help to avoid duplicating the help text. 03.01.01 [pre5] [df] Change raw keysyms to symbolic names in event.c. 02.01.01 [pre4] [df] Use NULL for the sentinel value in image_extentions. 02.01.01 [pre4] [df] Updated man page. 02.01.01 [pre4] [df] Replace random() with rand(), since the HAVE_RANDOM check didn't really work properly, rand is guaranteed to be there, and it's acceptible for the amount of randomness we need. This facilitated some more Makefile improvements. 02.01.01 [pre4] [df] Reorganized the source layout a bit. Optional code now lives in the lib/ dir. 02.01.01 [pre4] [df] Resync Makefile.Solaris to Makefile, and make some minor fixes to each. 01.01.01 [pre3] [df] Updated -e to work properly with the new centering stuff. This is now considered a feature, not a workaround ;-) 01.01.01 [pre3] [df] Put x and y hints into the window when we create it (should eliminate the "window pops up and then centers itself" problem.) 01.01.01 [pre3] [df] Removed last traces of wm_handle kludge, and set StaticGravity instead. 31.12.00 [pre3] [df] Only call gdk_show_window on load, not every single time we update. 31.12.00 [pre3] [df] Replaced strsort with qsort. (should be faster, doesn't have an illegal name ;-) 31.12.00 [pre3] [df] Replaced sprintf with snprintf and g_snprintf to prevent any possible overflows. 31.12.00 [pre3] [df] Cleaned up some extraneous blank lines in output. 05.12.00 [pre2] [ak] another PPC fix. 27.11.00 [pre1] [ak] changed "char c" to "int c" in options.c not worked with char on Linux/ppc (mailed by Jiri Masik ) 1.5 === 23.09.00 [pre3] [ak] Released v1.5 - new homepage: www.klografx.net/qiv/ 05.08.00 [pre3] [ak] cleaned up readmes.. 05.08.00 [pre2] [ak] changed up/down and left/right moving of the image. now the stuff works like in ACDSee (Win). 30.07.00 [pre1] [ak] added limits for moving. 1.4 === 28.07.00 [1.4] [ak] added solaris 2.5 patch from francois.petitjean@bureauveritas.com 25.07.00 [1.4] [ak] added image moving with left/right/up/down-keys! :) tried to fix reset_display_settings (b/g/c) but it dont work.. hm added zoom_out limits (64x64). changed keys: now K and L rotate the image. 1.4 === 25.06.00 [pre4] [da] Sending a SIGUSR1 to qiv will cause the program to flip to next picture. SIGUSR2 will move to previous. 15.06.00 [pre3] [ak] re-added b/c/g to titlebar/infoline. painted new intro.jpg *g* 29.04.00 [pre2] [al] image shuffling option (--shuffle) provides random image order while preserving next and previous functionality. 13.04.00 [pre1] [ak] cleaned up infoscreen/added more info and kicked "show_info". 03.04.00 [pre1] [da] The delay time in slideshow mode used to include the time it took for a picture to load. Pressing '?' in non-fullscreen mode results in the help being printed to stdout. 1.3 === 03.04.00 [pre4] [ak] updated man-page and info-screens. also added "qiv: " to title and info-bar. RELEASED v1.3-finale. 03.04.00 [pre4] [ab] patch to run a script called "qiv-command" with the key number and the filename as parameters. keys: 0-9. 13.02.00 [pre3] [de] utils.c patch. added recursive file retrieval (-u option) 30.10.99 [pre2] [ak] removed b/c/g limits to enable nice effects like b0/c-100/g0 :-) 05.10.99 [pre2] [ak] added SPEED_UP readme. 28.09.99 [pre2] [ak] added nice "infotext" stuff that shows a short info about the called function in the statusbar (maxspect: on/off and so..) 24.09.99 [pre1] [hk] started using a better random-slideshow generator. 1.2 === 23.09.99 [da] "?" patch :) 23.09.99 [aw] transparency bugfix. 17.06.99 [ak] no_replace is now default fpr random-slideshow. the parameter has been removed. 14.06.99 [ak] added TO-DO list 14.06.99 [ej] added slideshow_without_replacement_patch 1.1 === 27.04.99 [ak] added #include to image.c 21.04.99 [df] changed Makefile to use the system's getopt if it's availible, took the getopt section back out of README, updated install-xscreensaver to use -fitsd style options, fixed -h typo. 21.04.99 [pa] Included GNU getopt_long sources and deleted the non-getopt code from options.c. 20.04.99 [ak] kicked make test ;) now its in make install again. 20.04.99 [df] added HAVE_GETOPT_LONG conditional compilation stuff for Solaris/FreeBSD, rescued xscreensaver stuff from install.sh into Makefile, shuffled INSTALL into README and reformatted a bit. 20.04.99 [ak] kicked user_settings from qiv.h (nw in Makefile) added --help. small changes in manpage. 19.04.99 [df] rewrote Makefile (replacing install.sh), fixed syntax of -e, rewrote option-parsing code to use getopt, axed really long usage message, header file reorg. 17.04.99 [ak] removed prefix from install.sh. don't ask me why, but this don't works here with my bash 2.01 :( 15.04.99 [de] Makefile changes/additions (test/debug targets) Added prefix to install script 13.04.99 [ak] man page update, many tests, new image . 08.04.99 [pa] fixed the "-d 0" problem :-) 07.04.99 [pa] fixed the slideshow/key problems from pre4 with some glib versions. 06.04.99 [pa] slideshow fixes. [ak] removed old language.h/stuff. 02.04.99 [pa] Reorganized everything to use events and not to eat up 100% CPU time. Got rid of sleep() in slideshow, thus making qiv react faster. Random now works not only in slideshow. In random non-slideshow mode, terms "next image" and "previous image" are essentially the same, as they both are random. Image jumping uses main event handler now. 01.04.99 [pa] added utils.c patch for FreeBSD. 22.02.99 [to/ak] added 8bpp patch for better to_root drawing. 1.0.1 ===== 27.01.99 [ak] kicked the language stuff. updated manpage. tested with newest libraries (gtk/glib 1.1.13, Imlib 1.9.2). 19.11.98 [ak] addec --center, -e for disabling window_centering 13.11.98 [de] speed_ups 10.11.98 [ak] configure script, directiries for language files. added language-information to qiv -v 09.11.98 [de] incorporated Roland Trique's french documentation minor bug-fix to pointer/keyboard grabbing/ungrabbing 1.0 === 05.11.98 [ak] fixed --do_grab for wm=0 added --display and --wm to man-page made qiv ready for releasing 1.0 :-) added error_handler for set_background_image... painted a new and also wonderful intro.png (with the GIMP). 03.11.98 [ak] added gdk_beep(); for bad images (error handler). 03.11.98 [de] better WM_HANDLE= support. better command_line support for Solaris. 03.11.98 [ak] added window_manager_handling.. the damm center_stuff seems to be a general GDK problem :-( no way to fix it (at the moment).. so YOU must tell qiv which WM you are using.. see README selection "Center Problem".. 02.11.98 [de] removed getopt stuff (now qiv manually checks commandline options) 30.10.98 [ak] small changes in main.c: now --display :1 or so works. 27.10.98 [ak] added tga support to main.h/Makefile played with the "first window centered" problem.. it's not fixed 100%, but better then bevore :) 25.10.98 [de] changed bg_color option to use 24 bits (6 numbers - like HTML) cleaned up move2trash function 24.10.98 [de] added more color names 22.10.98 [de] --no_filter option works again added --bg_color (-o) option to change root background color when setting root background image with --root (-x) 20.10.98 [de] modification to bcg variable names to remove warning on Solaris mouse grabbing is no longer the default (use --do_grab (-a) to grab the pointer in windowed mode). 18.10.98 [ak] removed error_xpm. now we set only the background_color to blue. painted a wonderfull intro.jpg and added to make install. 17.10.98 [de] grouped functions into separate files 16.10.98 [de] added imlib dithering for 8 bit displays 15.10.98 [de] fixed another solaris issue with stdlib.h and random/srandom (see the Makefile if you're having problems compiling) 15.10.98 [ak] more comments, small changes in man-page... 14.10.98 [de] added --version, -v switch for version information 13.10.98 [ak] added --no_grab, -a for disabling keyboard/mouse grabbing in windowed mode. added -y/-x also for "no getopt.h"-users ;) 11.10.98 [de] cleaned up code for 1.0 release added x/y/z keys for setting bg (center/tile/stretched) while qiv is running removed x key from exit sequence added keyboard/mouse grabs to qiv (now fullscreen works right) changed mouse events to work off release instead of press --root_s, -z shows the image stretched on root. 11.10.98 [ak] --root. -x now center the image on root (can be used with -m or so..). --root_t, -y shows the image tiled on root. 08.10.98 [ak] added pnm support 0.9.1 (Solaris NOW!) ==================== 08.10.98 [ak] small changes in manpage.. 08.10.98 [de] made 0.9 ready for Soliaris/SunOS. (fixed getopt.h stuff). 0.9 === 04.10.98 [ak] added render_time (x.xs) to title- and statusbar. changed statusbar_color from white to orange. small code-cleanup. 04.10.98 [de] added more stuff to manpage. 03.10.98 [ak] removed doc/ and added qiv.1 to install.sh 03.10.98 [de] created manpage :) 03.10.98 [da] fixed problem with not taking into account the null terminator of some strings (char xyz[x+1]). 01.10.98 [ak] added --no_statusbar (-i) and i/I keys for on/off. added doc/ + install of README file. small changes in usage (its now smaller). fixed statusbar => works! :-) statusbar is now white - added black (1 pixel) border. Changes is now installed to. 30.09.98 [ak] fixed error_xpm.. now w=500 and h=400 in windowed and w=screen_x, h=screen_y (fullscreen) in fullscreen mode. collor is now BLUE :-) like "bluewin95" :)) statusbar added for fullscreen mode.. but its alpha, black text without a background color or so at the moment.. 30.09.98 [ak] happy birthday to me.. happy.. yes, i'm 20 now :) 29.09.98 [de] extension filter can be disabled now: --no_filter (-n) 28.09.98 [jk] fullscreen_mode: instead of blanking the whole window, blanks only the areas which aren't going to be covered by the picture. (?) 0.8.1 ===== 25.09.98 [de] bugfix: move2trash: the problem was that the subdirectories were NOT being created in the .qiv-trash directory. 25.09.98 [ak] removed the error.h (error_xpm[]) not you will get a black screen (500*400)... 0.8 === 22.09.98 [de] filter stuff: now non case-sensitive 23.09.98 [fc] fixed: transparency in fullscreen, jump2image 22.09.98 [ak] imlib_load error handler. 22.09.98 [de] changes on the filter stuff (+Makefile). adds rotate right/left, flip horizontal/vertical and some minor bug fixes to qiv. 18.09.98 [de] added image_filter, pre-increment and removed dir_check. 16.09.98 [de] jxx -> usage 16.09.98 [fc] bugfix (floating point exception). 16.09.98 [de] "jt15[enter]" - qiv should go to image 15, "jb5[enter]" - qiv should go back 5 images to image 10, "jf7[enter]" - qiv should go forward 7 images to image 17 15.09.98 [de] usage + b/c/g again. 15.09.98 [ak] small "--help" changes. sys/time.h :) 15.09.98 [de] b/c/g fix + delete (move to .qiv-trash) funktion :-) 15.09.98 [fc] fixes + comments. 15.09.98 [rn] fixed -r and order. 14.09.98 [ak] maxpect on/off keys: m/M and scale_down (t/T) -x (set X11 background) 14.09.98 [rn] code_rewrite (clean up) and maxpect 0.7 === 12.09.98: [de] random slideshow (-r), brightness, contrast and gamma. 09.09.98: [fc] code cleanup 0.6 === 09.09.98: [fc] full_screen mode and imwheel support. 08.09.98: [fc] slideshow and mouse-bindings :-) 0.5.2 ===== 07.09.98: [ak] fixed transparency again.. now it seems to work fine, but now all windows don't get a border (FVWM2).. 07.09.98: [ak] fixed 'first_window_was_not_centered'-bug.. 07.09.98: [sw] changes in auto_resize funktion. now only to large images will be scalled down. (a/A removed) 0.5.1 ===== 05.09.98: [ak] fixed transparency bug. 0.5 === 04.09.98: [ak] removed 200% zoom limit. 04.09.98: [ak] added s/S key for en- disabling autoresize + -DAUTORESIZE for enabling on startup. 04.09.98: [sw] auto_resize funktion. 04.09.98: [sw] auto_loop on next/prev image. 0.4 === 31.08.98: [ak] using gdk_imlib_kill_image for disabling Imlib-Caching. the caching is a verry good feature, but when you view 100 pictures or so then your system begins to swap.. 30.08.98: [hm/ak] loading of more than one pictures (*.jpg or so) 0.3 === 30.08.98: [ak] center_placement.. but this looks ugly because gdk (1.1.2(cvs)/FVWM2 with OpaqueMove) make a refresh beetwen resize and move :( any ideas ? on KWM this works fine... 29.08.98: [ak] fixed 100% 'bug' 0.2 === 29.08.89: [ss] min_zoom_size=5%, max=200%, auto-resize (window) qiv-3.0.1/README0000664000175000001440000000755514774332451012074 0ustar andyusersQuick Image Viewer (qiv) by Andy Spiegl http://qiv.spiegl.de/ - qiv.andy@spiegl.de --------------------------------------------------------------------------- Original author: Adam Kopacz / KLOGRAFX.DE Network http://www.klografx.net/qiv/ - adam.k@klografx.de =========================================================================== Installation (Linux/Solaris/FreeBSD): ------------------------------------- If you are using Debian/GNU Linux (or a derivative thereof) just type: dpkg-buildpackage -uc -B -m"your@email.address" -rfakeroot Various compile-time options are in the Makefile; be sure to at least read over them before typing "make install"... :) qiv-command ----------- Rename "qiv-command.example" to "qiv-command" and copy it in your path if you want to launch other programs within qiv. This is very nice for stuff like "metacam", "jhead", "exiftool" etc. to show the EXIF-infos of digital photos. If you get errors like this: "/bin/sh: pkg-config: command not found" then your Imlib is too old.. this means you don't have the program pkg-config. You should install pkg-config or replace the `pkg-config` calls in the Makefile: `pkg-config --cflags gdk-2.0 imlib2` --> -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/pango-1.0 \ -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/cairo \ -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 `pkg-config --libs gdk-2.0 imlib2` --> -lgdk-x11-2.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lgio-2.0 -lpango-1.0 \ -lcairo -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lImlib2 Solaris Users: please try "Makefile.Solaris" instead of "Makefile" if the default Makefile doesn't work for you. Other OSes: ---------- Try the Linux/Solaris/FreeBSD stuff... it would be nice if you could drop me some lines if qiv works also on other systems (HP-UX?) ... Authors: -------- Adam Kopacz Andy Spiegl Thomas Wiegner ...and many more (see Changelog and/or Homepage) Homepage: --------- http://qiv.spiegl.de/ Homepage of original author: ---------------------------- http://www.klografx.net/qiv/ Misc: ----- Thanx to all programers, Owen Taylor and Rasterman (@REDHAT) for helping with patches and their knowledge :-) type "man qiv" for more information. See the Makefile if you have problems compiling. qiv is designed to work with ANY gtk/gdk, it also should work with ANY version of Imlib of Linux (Intel/Mac), Solaris (SunOS) and FreeBSD. As of version 2.2 imlib2 and gdk-2.0 are required, as imlib1 and gtk-1.2 are basically obsolete. To use autorotation based on exif information gdk >= 2.12 is required. Up to release 1.3 of imlib2 there is a problem with the includes. Imlib2.h does not load Xlib.h. Workaround: to add the following (as very first line) to qiv.h: #include Centering: ---------- As of version 1.7, qiv centers images by applying the correct window position and setting the window gravity to Static, so that window managers don't move the window when adding borders. If you come across a window manager that does mess up our centering, or has other problems with qiv, email Decklin (decklin@red-bean.com) and he'll quickly send off a patch to whoever maintains that WM. ;-) Thumbnails: ----------- we don't plan on adding a thumbnail function. sorry, but qiv is a QUICK image VIEWER and nothing more. if you want more features (with Imlib) then try Electric Eyes or gqview or feh ... Links: ------ ImLib2 : http://freshmeat.net/projects/imlib2/ gtk/gdk : http://www.gtk.org/ qiv-orig : http://www.klografx.net/qiv/ qiv : http://qiv.spiegl.de/ git-repo : https://codeberg.org/ciberandy/qiv.git Contact: -------- Mail bug, reports and comments to Andy Spiegl qiv-3.0.1/Makefile0000664000175000001440000001261414774332451012644 0ustar andyusers####################################################################### # Makefile for qiv - Quick Image Viewer - http://qiv.spiegl.de/ # User Options ####################################################################### # Directory where qiv will be installed under. PREFIX = /usr/local # Fonts to use for statusbar and comments STATUSBAR_FONT = "Monospace 9" COMMENT_FONT = "Monospace 20" ARTIST_FONT = "Monospace 10" # Cursor to use on qiv windows - see # /usr/X11R6/include/X11/cursorfont.h for more choices. CURSOR = 84 # Should image be centered on screen by default? 1=yes, 0=no. CENTER = 1 # Should images be filtered by extension? 1=yes, 0=no. FILTER = 1 # This sets the file extentions to filter on (other file types will be # skipped.) It should reflect whatever can be loaded via gdk-pixbuf-loader. EXTNS = GIF TIFF XPM PNG PPM PNM PGM PCX BMP EIM JPEG SVG WMF ICO WEBP HEIF # Comment this line out if your system doesn't have getopt_long(). GETOPT_LONG = -DHAVE_GETOPT_LONG # This program will be run on the manual page after it is installed. # If you don't want to compress the manpage, change it to 'true'. COMPRESS_PROG = gzip -9f # Comment this line out if your system doesn't have lcms2 installed # (for minimal Color Management support) LCMS = -DSUPPORT_LCMS # Comment this line out if you do not want to use libmagic to # identify if a file is an image MAGIC = -DHAVE_MAGIC # Comment this line out if you do not want to use libexif to # display the exif contents of a jpg EXIF = -DHAVE_EXIF ###################################################################### # Variables and Rules # Do not edit below here! ###################################################################### ifeq ($(origin CC),default) CC = gcc endif PKG_CONFIG ?= pkg-config INSTALL ?= install CFLAGS = -O2 -Wall \ -fcaller-saves -ffast-math -fno-strength-reduce \ -fthread-jumps GDK_VERS := 3 ifeq ($(GDK_VERS), 3) INCLUDES := $(shell $(PKG_CONFIG) --cflags gdk-3.0 ) LIBS := $(shell $(PKG_CONFIG) --libs gdk-3.0 ) -lX11 -lXext -lgio-2.0 else INCLUDES := $(shell $(PKG_CONFIG) --cflags gdk-2.0) LIBS := $(shell $(PKG_CONFIG) --libs gdk-2.0) -lX11 -lXext -lgio-2.0 endif # [as] thinks that this is not portable enough: # [lc] I use a virtual screen of 1600x1200, and the resolution is 1024x768, # so I changed (in main.c) how screen_[x,y] is obtained; it seems that gtk # 1.2 cannot give the geometry of viewport, so I borrowed from the source # of xvidtune the code for calling XF86VidModeGetModeLine, this requires # the linking option -lXxf86vm. #LIBS += -lXxf86vm PROGRAM = qiv OBJS = main.o image.o event.o options.o utils.o xmalloc.o HEADERS = qiv.h DEFINES = $(patsubst %,-DEXTN_%, $(EXTNS)) \ $(GETOPT_LONG) \ -DSTATUSBAR_FONT='$(STATUSBAR_FONT)' \ -DCOMMENT_FONT='$(COMMENT_FONT)' \ -DARTIST_FONT='$(ARTIST_FONT)' \ -DCENTER=$(CENTER) \ -DFILTER=$(FILTER) \ -DCURSOR=$(CURSOR) \ $(MAGIC) \ $(EXIF) \ $(LCMS) ifndef GETOPT_LONG OBJS += lib/getopt.o lib/getopt1.o OBJS_G += lib/getopt.g lib/getopt1.g endif ifdef LCMS INCLUDES += $(shell $(PKG_CONFIG) --cflags lcms2) LIBS += $(shell $(PKG_CONFIG) --libs lcms2) -ljpeg -ltiff endif ifdef EXIF INCLUDES += $(shell $(PKG_CONFIG) --cflags libexif) LIBS += $(shell $(PKG_CONFIG) --libs libexif) endif ifdef MAGIC LIBS += -lmagic endif PROGRAM_G = qiv-g OBJS_G = $(OBJS:.o=.g) DEFINES_G = $(DEFINES) -DDEBUG ###################################################################### all: $(PROGRAM) $(PROGRAM): $(OBJS) $(CC) $(CFLAGS) $(DEFINES) $(OBJS) $(LIBS) -o $(PROGRAM) $(OBJS): %.o: %.c $(HEADERS) Makefile $(CC) -c $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $@ main.o: main.h ###################################################################### debug: $(PROGRAM_G) $(PROGRAM_G): $(OBJS_G) $(CC) -g $(CFLAGS) $(DEFINES_G) $(OBJS_G) $(LIBS) -o $(PROGRAM_G) $(OBJS_G): %.g: %.c $(HEADERS) $(CC) -c -g $(CFLAGS) $(DEFINES_G) $(INCLUDES) $< -o $@ ###################################################################### clean : @echo "Cleaning up..." rm -f $(OBJS) $(OBJS_G) distclean : clean rm -f $(PROGRAM) $(PROGRAM_G) install: $(PROGRAM) @echo "Installing QIV..." @if [ ! -e $(PREFIX)/bin ]; then \ $(INSTALL) -d -m 0755 $(PREFIX)/bin; \ echo install -d -m 0755 $(PREFIX)/bin; \ fi $(INSTALL) -s -m 0755 $(PROGRAM) $(PREFIX)/bin @if [ ! -e $(PREFIX)/share/man/man1 ]; then \ echo install -d -m 0755 $(PREFIX)/share/man/man1; \ $(INSTALL) -d -m 0755 $(PREFIX)/share/man/man1; \ fi $(INSTALL) -m 0644 $(PROGRAM).1 $(PREFIX)/share/man/man1 $(COMPRESS_PROG) $(PREFIX)/share/man/man1/$(PROGRAM).1 @if [ ! -e $(PREFIX)/share/pixmaps ]; then \ echo install -d -m 0755 $(PREFIX)/share/pixmaps; \ $(INSTALL) -d -m 0755 $(PREFIX)/share/pixmaps; \ fi $(INSTALL) -m 0644 qiv.png $(PREFIX)/share/pixmaps/qiv.png @if [ ! -e $(PREFIX)/share/applications ]; then \ echo install -d -m 0755 $(PREFIX)/share/applications; \ $(INSTALL) -d -m 0755 $(PREFIX)/share/applications; \ fi $(INSTALL) -m 0644 qiv.desktop $(PREFIX)/share/applications/qiv.desktop @if ./qiv -f ./intro.jpg ; \ then echo "-- Test Passed --" ; \ else echo "-- Test Failed --" ; \ fi @echo "\nDont forget to look into the \"qiv-command\" file and install it!\n-> cp qiv-command.example $(PREFIX)/bin/qiv-command\n\n" # the end... ;-) qiv-3.0.1/event.c0000664000175000001440000011552114774332451012472 0ustar andyusers/* Module : event.c Purpose : Handle GDK events More : see qiv README Policy : GNU GPL Homepage : http://qiv.spiegl.de/ Original : http://www.klografx.net/qiv/ */ #include #include #include #include #include #include "qiv.h" #define STEP 3 //When using KP arrow, number of step for seeing all the image. static int jumping; static int extcommand; // [lc] static char jcmd[100]; static int jidx; static int cursor_timeout; static gboolean displaying_textwindow = FALSE; static void qiv_enable_mouse_events(qiv_image *q) { gdk_window_set_events(q->win, gdk_window_get_events(q->win) & ~GDK_POINTER_MOTION_HINT_MASK); } static void qiv_disable_mouse_events(qiv_image *q) { gdk_window_set_events(q->win, gdk_window_get_events(q->win) | GDK_POINTER_MOTION_HINT_MASK); } static gboolean qiv_cursor_timeout(gpointer data) { qiv_image *q = data; cursor_timeout = 0; hide_cursor(q); qiv_enable_mouse_events(q); return FALSE; } static void qiv_set_cursor_timeout(qiv_image *q) { if (!cursor_timeout) cursor_timeout = g_timeout_add(1000, qiv_cursor_timeout, q); qiv_disable_mouse_events(q); } static void qiv_cancel_cursor_timeout(qiv_image *q) { hide_cursor(q); if (cursor_timeout) { g_source_remove(cursor_timeout); cursor_timeout = 0; } } static void qiv_drag_image(qiv_image *q, int move_to_x, int move_to_y, const char *action_msg, const char *stalled_msg) { int moved = 0; if (move_to_x < 0 - q->win_w) move_to_x = 0 - q->win_w; else if (move_to_x > monitor[q->mon_id].width) move_to_x = monitor[q->mon_id].width; if (q->win_x != move_to_x) { q->win_x = move_to_x; moved = 1; } if (move_to_y < 0 - q->win_h) move_to_y = 0 - q->win_h; else if (move_to_y > monitor[q->mon_id].height) move_to_y = monitor[q->mon_id].height; if (q->win_y != move_to_y) { q->win_y = move_to_y; moved = 1; } if (moved || !stalled_msg) snprintf(infotext, sizeof infotext, "%s", action_msg); else snprintf(infotext, sizeof infotext, "%s", stalled_msg); update_image(q, MOVED); } void qiv_display_text_window(qiv_image *q, const char *infotextdisplay, const char *strs[], const char *continue_msg) { int temp, text_w = 0, text_h, i, maxlines; int width, height, text_left; int ascent; int descent; cairo_t *cr; ascent = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics)); descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics)); if (fullscreen) { width = monitor[q->mon_id].width; height = monitor[q->mon_id].height; } else { width = q->win_w; height = q->win_h; } /* Calculate maximum number of lines to display */ if (ascent + descent > 0) maxlines = height / (ascent + descent) - 3; else maxlines = 60; pango_layout_set_text(layout, continue_msg, -1); pango_layout_get_pixel_size (layout, &text_w, NULL); for (i = 0; strs[i] && i < maxlines; i++) { pango_layout_set_text(layout, strs[i], -1); pango_layout_get_pixel_size (layout, &temp, NULL); if (text_w < temp) text_w = temp; } text_h = (i + 2) * ( ascent + descent ); snprintf(infotext, sizeof infotext, "%s", infotextdisplay); update_image(q, MIN_REDRAW); text_left = width/2 - text_w/2 - 4; if (text_left < 2) text_left = 2; /* if window/screen is smaller than text */ cr = gdk_cairo_create (q->win); set_cairo_color(cr, 0); cairo_rectangle(cr, text_left, height/2 - text_h/2 - 4, text_w+7, text_h+7); cairo_fill (cr); set_cairo_color(cr, STATUSBAR_BG); cairo_rectangle(cr, text_left + 1, height/2 - text_h/2 - 3, text_w+5, text_h+5); cairo_fill (cr); set_cairo_color(cr, 0); for (i = 0; strs[i] && i < maxlines; i++) { pango_layout_set_text(layout, strs[i], -1); cairo_move_to (cr, text_left + 4, height/2 - text_h/2 + i * (ascent + descent)); pango_cairo_show_layout(cr, layout); } /* Display Push Any Key... message */ pango_layout_set_text(layout, continue_msg, -1); pango_layout_get_pixel_size (layout, &temp, NULL); cairo_move_to (cr, width/2 - temp/2, height/2 - text_h/2 - descent + (i+1)*(ascent + descent)); pango_cairo_show_layout(cr, layout); cairo_destroy(cr); displaying_textwindow = TRUE; /* print also on console */ if (0) { int i; for (i = 0; strs[i] != NULL; i++) { printf("%s\n", strs[i]); } } } void qiv_handle_event(GdkEvent *ev, gpointer data) { gboolean exit_slideshow = FALSE; qiv_image *q = data; int move_step; const char *mess[2]={ jcmd, NULL}; // get windows position if not in fullscreen mode // (because the user might have moved the window our since last redraw) if (!fullscreen) { gdk_window_get_position(q->win, &q->win_x, &q->win_y); // g_print("position : q->win_x = %d, q->win_y = %d, q->win_w = %d, mon = %d, typ = %d\n", q->win_x, q->win_y, q->win_w,q->mon_id,ev->type); } q->mon_id = gdk_screen_get_monitor_at_window(screen, q->win); switch(ev->type) { case GDK_DELETE: qiv_exit(0); break; case GDK_EXPOSE: if (!q->exposed) { qiv_set_cursor_timeout(q); if(center) center_image(q); } if(fullscreen) { update_image(q, FULL_REDRAW); } else { if(q->exposed) update_image(q, MIN_REDRAW); else update_image(q, FULL_REDRAW); } q->exposed = 1; break; case GDK_LEAVE_NOTIFY: if (magnify && !fullscreen) { gdk_window_hide(magnify_img.win); } gdk_pointer_ungrab(CurrentTime); gdk_keyboard_ungrab(CurrentTime); break; case GDK_ENTER_NOTIFY: if(do_grab || (fullscreen && !disable_grab)) { gdk_keyboard_grab(q->win, FALSE, CurrentTime); gdk_pointer_grab(q->win, FALSE, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK, NULL, NULL, CurrentTime); } case GDK_CONFIGURE: if (magnify && !fullscreen) { gdk_window_get_root_origin(q->win, &magnify_img.frame_x, &magnify_img.frame_y); // printf("GDK_CONFIGURE get_root_origin %d %d\n", // magnify_img.frame_x, magnify_img.frame_y); } break; case GDK_BUTTON_PRESS: jumping=0; /* abort jump mode if a button is pressed */ qiv_cancel_cursor_timeout(q); if (fullscreen && ev->button.button == 1) { q->drag = 1; // q->drag_start_x = ev->button.x; // q->drag_start_y = ev->button.y; q->drag_start_x = ev->button.x_root; q->drag_start_y = ev->button.y_root; q->drag_win_x = q->win_x; q->drag_win_y = q->win_y; qiv_enable_mouse_events(q); } break; case GDK_MOTION_NOTIFY: if (q->drag) { int move_x, move_y; move_x = (int)(ev->button.x_root - q->drag_start_x); move_y = (int)(ev->button.y_root - q->drag_start_y); if (q->drag == 1 && (ABS(move_x) > 3 || ABS(move_y) > 3)) { /* distinguish from simple mouse click... */ q->drag = 2; show_cursor(q); } if (q->drag > 1 && (q->win_x != q->drag_win_x + move_x || q->win_y != q->drag_win_y + move_y)) { GdkEvent *e; qiv_disable_mouse_events(q); qiv_drag_image(q, q->drag_win_x + move_x, q->drag_win_y + move_y, "(Drag)", NULL); /* el cheapo mouse motion compression */ while (gdk_events_pending()) { /* [tw] why check if "e" not NULL? */ if((e = gdk_event_get())) { if (e->type == GDK_BUTTON_RELEASE) { gdk_event_put(e); gdk_event_free(e); break; } gdk_event_free(e); } } qiv_enable_mouse_events(q); } } else { show_cursor(q); // printf(" motion_notify magnify %d is_hint %d\n", magnify, ev->motion.is_hint); if (magnify && !fullscreen) { gint xcur, ycur; if (ev->motion.is_hint) { gdk_window_get_pointer(q->win, &xcur, &ycur, NULL); update_magnify(q, &magnify_img,REDRAW, xcur, ycur); // [lc] } // update_magnify(q, &magnify_img,REDRAW, ev->motion.x, ev->motion.y); } else { qiv_set_cursor_timeout(q); } } break; /* Use release instead of press (Fixes bug with junk being sent * to underlying xterm window on exit) */ case GDK_BUTTON_RELEASE: exit_slideshow = TRUE; switch (ev->button.button) { /* [tw]: buttons 4-7 don't work in GDK-2.0 as button events, * they are now GDK_SCROLL events */ case 1: /* left button pressed */ displaying_textwindow = FALSE; if (q->drag) { int move_x, move_y; // move_x = (int)(ev->button.x - q->drag_start_x); // move_y = (int)(ev->button.y - q->drag_start_y); move_x = (int)(ev->button.x_root - q->drag_start_x); move_y = (int)(ev->button.y_root - q->drag_start_y); qiv_disable_mouse_events(q); qiv_set_cursor_timeout(q); if (q->drag > 1) { qiv_drag_image(q, q->drag_win_x + move_x, q->drag_win_y + move_y, "(Drag)", NULL); q->drag = 0; break; } q->drag = 0; } goto next_image; case 8: displaying_textwindow = FALSE; goto zoom_out; case 9: displaying_textwindow = FALSE; goto zoom_in; default: g_print("unmapped button event %d, exiting\n",ev->button.button); case 2: /* middle button pressed */ qiv_exit(0); break; case 3: /* right button pressed */ displaying_textwindow = FALSE; goto previous_image; break; } break; case GDK_SCROLL: displaying_textwindow = FALSE; switch (ev->scroll.direction) { case GDK_SCROLL_UP: if (fullscreen) { if (ev->key.state & GDK_SHIFT_MASK) { move_step = (MIN(monitor[q->mon_id].height, q->win_h) / STEP); } else { move_step = (q->win_h / 100); } if (move_step < 10) move_step = 10; qiv_drag_image(q, q->win_x, q->win_y + move_step, "(Moving down)", "(Cannot move further down)"); } else { snprintf(infotext, sizeof infotext, "(5 pictures back)"); next_image(-5); if(magnify && !fullscreen) gdk_window_hide(magnify_img.win); // [lc] qiv_load_image(q); } break; case GDK_SCROLL_DOWN: if (fullscreen) { if (ev->key.state & GDK_SHIFT_MASK) { move_step = (MIN(monitor[q->mon_id].height, q->win_h) / STEP); } else { move_step = (q->win_h / 100); } if (move_step < 10) move_step = 10; qiv_drag_image(q, q->win_x, q->win_y - move_step, "(Moving up)", "(Cannot move further up)"); } else { snprintf(infotext, sizeof infotext, "(5 pictures forward)"); next_image(5); if(magnify && !fullscreen) gdk_window_hide(magnify_img.win); // [lc] qiv_load_image(q); } break; case GDK_SCROLL_LEFT: if (fullscreen) { if (ev->key.state & GDK_SHIFT_MASK) { move_step = (MIN(monitor[q->mon_id].width, q->win_w) / STEP); } else { move_step = (q->win_w / 100); } if (move_step < 10) move_step = 10; qiv_drag_image(q, q->win_x + move_step, q->win_y, "(Moving right)", "(Cannot move further right)"); } else { snprintf(infotext, sizeof infotext, "(Previous picture)"); next_image(-1); if(magnify && !fullscreen) gdk_window_hide(magnify_img.win); // [lc] qiv_load_image(q); } break; case GDK_SCROLL_RIGHT: if (fullscreen) { if (ev->key.state & GDK_SHIFT_MASK) { move_step = (MIN(monitor[q->mon_id].width, q->win_w) / STEP); } else { move_step = (q->win_w / 100); } if (move_step < 10) move_step = 10; qiv_drag_image(q, q->win_x - move_step, q->win_y, "(Moving left)", "(Cannot move further left)"); } else { snprintf(infotext, sizeof infotext, "(Next picture)"); next_image(1); if(magnify && !fullscreen) gdk_window_hide(magnify_img.win); // [lc] qiv_load_image(q); } break; default: break; } break; case GDK_KEY_PRESS: { exit_slideshow = TRUE; /* Abort slideshow on any key by default */ qiv_cancel_cursor_timeout(q); #ifdef DEBUG g_print("*** key:\n"); /* display key-codes */ g_print("\tstring: %s\n",ev->key.string); g_print("\tkeyval: %d\n",ev->key.keyval); #endif if (displaying_textwindow && !extcommand ) { // [lc] /* Hide the text window if it is showing */ displaying_textwindow = FALSE; if(fullscreen) { update_image(q, FULL_REDRAW); } else { update_image(q, MIN_REDRAW); } break; } if (jumping || extcommand) { // [lc] todo: Backspace, if(ev->key.keyval == GDK_KEY_Escape) { extcommand = 0; jidx = 0; displaying_textwindow = FALSE; update_image(q, FULL_REDRAW); break; } if(ev->key.keyval == GDK_KEY_BackSpace) { jidx--; jcmd[jidx]='\0'; qiv_display_text_window(q, "(Sending Command)", mess, "Press to send, to abort"); // [lc] break; } if((ev->key.keyval == GDK_KEY_Return) || (ev->key.keyval == GDK_KEY_KP_Enter) || (jidx == 99)) { /* 99 digits already typed */ jcmd[jidx] = '\0'; if (jumping) { jump2image(jcmd); qiv_load_image(q); jumping=0; } else { // extcommand=1 int numlines = 0; const char **lines; extcommand=0; /* Hide the text window if it is showing */ displaying_textwindow = FALSE; update_image(q, MIN_REDRAW); run_command(q, jcmd, image_names[image_idx], &numlines, &lines); if (lines && numlines) qiv_display_text_window(q, "(Command output)", lines, "Push any key..."); } } /* else record keystroke if not null */ else if(ev->key.string && *(ev->key.string) != '\0') { if (jumping) { /* leave jumping mode on invalid input and process * input key as if it entered in non jumping mode */ if((jidx == 0 && (*(ev->key.string) != 'f' && *(ev->key.string) != 'F' && *(ev->key.string) != 'b' && *(ev->key.string) != 'B' && *(ev->key.string) != 't' && *(ev->key.string) != 'T')) || (jidx > 0 && (*(ev->key.string) < '0' || *(ev->key.string) > '9'))) { jumping = 0; qiv_handle_event(ev, data); return; } } jcmd[jidx++]=*(ev->key.string); jcmd[jidx] = '\0'; if (extcommand) qiv_display_text_window(q, "(Sending Command)", mess, "Press to send, to abort"); // [lc] } } else { guint keyval = ev->key.keyval; if(vikeys) { if (keyval == 'h') keyval = GDK_KEY_Left; else if (keyval == 'j') keyval = GDK_KEY_Down; else if (keyval == 'k') keyval = GDK_KEY_Up; else if (keyval == 'l') keyval = GDK_KEY_Right; else switch (keyval) { case 'H': case 'J': case 'K': case 'L': keyval = tolower(keyval); break; } } switch (keyval) { /* Help */ case '?': case GDK_KEY_F1: qiv_display_text_window(q, "(Showing Help)", helpstrs,"Press any key..."); break; /* Exit */ case GDK_KEY_Escape: case 'q': qiv_exit(0); break; /* Fullscreen mode (on/off) */ case 'f': exit_slideshow = FALSE; gdk_window_withdraw(q->win); show_cursor(q); fullscreen ^= 1; first=1; qiv_load_image(q); break; /* Center mode (on/off) */ case 'e': exit_slideshow = FALSE; center ^= 1; snprintf(infotext, sizeof infotext, center ? "(Centering: on)" : "(Centering: off)"); if (center) center_image(q); update_image(q, MOVED); break; /* Display exif information */ #ifdef HAVE_EXIF case 'E': { char **lines; int i=0; lines=get_exif_values(image_names[image_idx]); if(lines) { qiv_display_text_window(q, "(Exif Info)", (const char**) lines,"Press any key..."); /* free all the mem malloc'ed by get_exif_values func */ while(*(lines+i) != NULL) { free(*(lines+i)); i++; } free(lines); } } break; #endif /* Transparency on/off */ case 'p': exit_slideshow = FALSE; transparency ^= 1; snprintf(infotext, sizeof infotext, transparency ? "(Transparency: on)" : "(Transparency: off)"); update_image(q, MIN_REDRAW); break; /* Maxpect on/off */ case 'm': scale_down = 0; maxpect ^= 1; snprintf(infotext, sizeof infotext, maxpect ? "(Maxpect: on)" : "(Maxpect: off)"); zoom_factor = maxpect ? 0 : fixed_zoom_factor; /* reset zoom */ check_size(q, TRUE); update_image(q, REDRAW); break; /* Random on/off */ case 'r': random_order ^= 1; snprintf(infotext, sizeof infotext, random_order ? "(Random order: on)" : "(Random order: off)"); update_image(q, REDRAW); break; /* iconify */ case 'I': exit_slideshow = TRUE; if (fullscreen) { gdk_window_withdraw(q->win); show_cursor(q); qiv_set_cursor_timeout(q); fullscreen=0; first=1; qiv_load_image(q); } gdk_window_iconify(q->win); /* Statusbar on/off */ case 'i': exit_slideshow = FALSE; if (fullscreen) { statusbar_fullscreen ^= 1; snprintf(infotext, sizeof infotext, statusbar_fullscreen ? "(Statusbar: on)" : "(Statusbar: off)"); } else { statusbar_window ^= 1; snprintf(infotext, sizeof infotext, statusbar_window ? "(Statusbar: on)" : "(Statusbar: off)"); } update_image(q, MIN_REDRAW); break; /* jpeg comments on/off */ case 'J': exit_slideshow = FALSE; comment_window ^= 1; snprintf(infotext, sizeof infotext, comment_window ? "(Comments: on)" : "(Comments: off)"); if (fullscreen) { /* REDRAW or MIN_REDRAW is not enough if the text window is outside the image area */ update_image(q, FULL_REDRAW); } else { update_image(q, MIN_REDRAW); } break; /* artist name on/off */ case 'A': exit_slideshow = FALSE; artist_window ^= 1; snprintf(infotext, sizeof infotext, artist_window ? "(Artist: on)" : "(Artist: off)"); if (fullscreen) { /* REDRAW or MIN_REDRAW is not enough if the text window is outside the image area */ update_image(q, FULL_REDRAW); } else { update_image(q, MIN_REDRAW); } break; /* Slide show on/off */ case 's': exit_slideshow = FALSE; slide ^= 1; if (slide) { dpms_disable(); } snprintf(infotext, sizeof infotext, slide ? "(Slideshow: on)" : "(Slideshow: off)"); update_image(q, MIN_REDRAW); break; /* move image right */ case GDK_KEY_Left: case GDK_KEY_KP_4: case GDK_KEY_KP_Left: if (fullscreen) { if (ev->key.state & GDK_SHIFT_MASK || ev->key.keyval == GDK_KEY_KP_4) { move_step = (MIN(monitor[q->mon_id].width, q->win_w) / STEP); } else { move_step = (q->win_w / 100); } if (move_step < 10) move_step = 10; qiv_drag_image(q, q->win_x + move_step, q->win_y, "(Moving right)", "(Cannot move further right)"); } else { // snprintf(infotext, sizeof infotext, "(Moving works only in fullscreen mode)"); // fprintf(stdout, "qiv: Moving works only in fullscreen mode\n"); snprintf(infotext, sizeof infotext, "(Previous picture)"); next_image(-1); if(magnify && !fullscreen) gdk_window_hide(magnify_img.win); // [lc] qiv_load_image(q); } break; /* move image left */ case GDK_KEY_Right: case GDK_KEY_KP_6: case GDK_KEY_KP_Right: if (fullscreen) { if (ev->key.state & GDK_SHIFT_MASK || ev->key.keyval == GDK_KEY_KP_6) { move_step = (MIN(monitor[q->mon_id].width, q->win_w) / STEP); } else { move_step = (q->win_w / 100); } if (move_step < 10) move_step = 10; qiv_drag_image(q, q->win_x - move_step, q->win_y, "(Moving left)", "(Cannot move further left)"); } else { // snprintf(infotext, sizeof infotext, "(Moving works only in fullscreen mode)"); // fprintf(stdout, "qiv: Moving works only in fullscreen mode\n"); snprintf(infotext, sizeof infotext, "(Next picture)"); next_image(1); if(magnify && !fullscreen) gdk_window_hide(magnify_img.win); // [lc] qiv_load_image(q); } break; /* move image up */ case GDK_KEY_Down: case GDK_KEY_KP_2: case GDK_KEY_KP_Down: if (fullscreen) { if (ev->key.state & GDK_SHIFT_MASK || ev->key.keyval == GDK_KEY_KP_2) { move_step = (MIN(monitor[q->mon_id].height, q->win_h) / STEP); } else { move_step = (q->win_h / 100); } if (move_step < 10) move_step = 10; qiv_drag_image(q, q->win_x, q->win_y - move_step, "(Moving up)", "(Cannot move further up)"); } else { snprintf(infotext, sizeof infotext, "(Moving works only in fullscreen mode)"); fprintf(stdout, "qiv: Moving works only in fullscreen mode\n"); } break; /* move image down */ case GDK_KEY_Up: case GDK_KEY_KP_8: case GDK_KEY_KP_Up: if (fullscreen) { if (ev->key.state & GDK_SHIFT_MASK || ev->key.keyval == GDK_KEY_KP_8) { move_step = (MIN(monitor[q->mon_id].height, q->win_h) / STEP); } else { move_step = (q->win_h / 100); } if (move_step < 10) move_step = 10; qiv_drag_image(q, q->win_x, q->win_y + move_step, "(Moving down)", "(Cannot move further down)"); } else { snprintf(infotext, sizeof infotext, "(Moving works only in fullscreen mode)"); fprintf(stdout, "qiv: Moving works only in fullscreen mode\n"); } break; /* Scale_down */ case 't': maxpect = 0; scale_down ^= 1; snprintf(infotext, sizeof infotext, scale_down ? "(Scale down: on)" : "(Scale down: off)"); zoom_factor = maxpect ? 0 : fixed_zoom_factor; /* reset zoom */ check_size(q, TRUE); update_image(q, REDRAW); break; /* Resize + */ case GDK_KEY_KP_Add: case '+': case '=': zoom_in: if (magnify && !fullscreen) { gint xcur, ycur; magnify_img.zoom *= 1.1; gdk_window_get_pointer(q->win, &xcur, &ycur, NULL); update_magnify(q, &magnify_img,REDRAW, xcur, ycur); // [lc] } else { snprintf(infotext, sizeof infotext, "(Zoomed in)"); zoom_in(q); update_image(q, ZOOMED); } break; /* Resize - */ case GDK_KEY_KP_Subtract: case '-': zoom_out: if (magnify && !fullscreen) { if (magnify_img.zoom > 2.0) { gint xcur, ycur; magnify_img.zoom /= 1.1; if (magnify_img.zoom < 2) magnify_img.zoom = 2.0; gdk_window_get_pointer(q->win, &xcur, &ycur, NULL); update_magnify(q, &magnify_img,REDRAW, xcur, ycur); } } else { snprintf(infotext, sizeof infotext, "(Zoomed out)"); zoom_out(q); update_image(q, ZOOMED); } break; /* Reset Image / Original (best fit) size */ case GDK_KEY_Return: case GDK_KEY_KP_Enter: snprintf(infotext, sizeof infotext, "(Reset size)"); reload_image(q); zoom_factor = fixed_zoom_factor; /* reset zoom */ check_size(q, TRUE); update_image(q, REDRAW); break; /* Next picture - or loop to the first */ case ' ': next_image: snprintf(infotext, sizeof infotext, "(Next picture)"); next_image(1); qiv_load_image(q); if(magnify && !fullscreen) { gdk_window_hide(magnify_img.win); // [lc] // gdk_flush(); // gdk_window_get_root_origin(q->win, // &magnify_img.frame_x, &magnify_img.frame_y); // printf(">>> frame %d %d\n", magnify_img.frame_x, magnify_img.frame_y); // setup_magnify(q, &magnify_img); } break; /* 5 pictures forward - or loop to the beginning */ case GDK_KEY_Page_Down: case GDK_KEY_KP_Page_Down: snprintf(infotext, sizeof infotext, "(5 pictures forward)"); next_image(5); if(magnify && !fullscreen) gdk_window_hide(magnify_img.win); // [lc] qiv_load_image(q); break; /* Previous picture - or loop back to the last */ case GDK_KEY_BackSpace: previous_image: snprintf(infotext, sizeof infotext, "(Previous picture)"); next_image(-1); if(magnify && !fullscreen) gdk_window_hide(magnify_img.win); // [lc] qiv_load_image(q); break; /* 5 pictures backward - or loop back to the last */ case GDK_KEY_Page_Up: case GDK_KEY_KP_Page_Up: snprintf(infotext, sizeof infotext, "(5 pictures backward)"); next_image(-5); if(magnify && !fullscreen) gdk_window_hide(magnify_img.win); // [lc] qiv_load_image(q); break; /* + brightness */ case 'B': snprintf(infotext, sizeof infotext, "(More brightness)"); q->mod.brightness += 8; update_image(q, REDRAW); break; /* - brightness */ case 'b': snprintf(infotext, sizeof infotext, "(Less brightness)"); q->mod.brightness -= 8; update_image(q, REDRAW); break; /* + contrast */ case 'C': snprintf(infotext, sizeof infotext, "(More contrast)"); q->mod.contrast += 8; update_image(q, REDRAW); break; /* - contrast */ case 'c': snprintf(infotext, sizeof infotext, "(Less contrast)"); q->mod.contrast -= 8; update_image(q, REDRAW); break; /* + gamma */ case 'G': snprintf(infotext, sizeof infotext, "(More gamma)"); q->mod.gamma += 8; update_image(q, REDRAW); break; /* - gamma */ case 'g': snprintf(infotext, sizeof infotext, "(Less gamma)"); q->mod.gamma -= 8; update_image(q, REDRAW); break; /* - reset brightness, contrast and gamma */ case 'o': snprintf(infotext, sizeof infotext, "(Reset bri/con/gam)"); reset_mod(q); update_image(q, REDRAW); break; /* Delete image */ case GDK_KEY_Delete: case 'd': { int ret; if (!readonly) { if (trashbin == 1) ret = move2trashbin(); else ret = move2trash(); if (ret == 0) snprintf(infotext, sizeof infotext, "(Deleted last image)"); else snprintf(infotext, sizeof infotext, "(Delete FAILED)"); qiv_load_image(q); } break; } /* Undelete image */ case 'u': if (!readonly && !trashbin) { if (undelete_image() == 0) snprintf(infotext, sizeof infotext, "(Undeleted)"); else snprintf(infotext, sizeof infotext, "(Undelete FAILED)"); qiv_load_image(q); } break; /* Copy image to selected directory */ case 'a': if (copy2select() == 0) snprintf(infotext, sizeof infotext, "(Last image copied)"); else snprintf(infotext, sizeof infotext, "(Selection FAILED)"); next_image(1); qiv_load_image(q); break; /* Jump to image */ case 'j': jumping=1; jidx=0; break; /* Flip horizontal */ case 'h': { GdkPixbuf* pb_flipped = gdk_pixbuf_flip(q->pb, TRUE); g_object_unref(q->pb); q->pb = pb_flipped; snprintf(infotext, sizeof infotext, "(Flipped horizontally)"); update_image(q, REDRAW); break; } /* Flip vertical */ case 'v': { GdkPixbuf* pb_flipped = gdk_pixbuf_flip(q->pb, FALSE); g_object_unref(q->pb); q->pb = pb_flipped; snprintf(infotext, sizeof infotext, "(Flipped vertically)"); update_image(q, REDRAW); break; } /* Watch File (on/off) */ case 'w': watch_file ^= 1; snprintf(infotext, sizeof infotext, watch_file ? "(File watching: on)" : "(File watching: off)"); update_image(q, MIN_REDRAW); if(watch_file){ // check every 100ms g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 100, qiv_watch_file, q, NULL); } break; /* Rotate right */ case 'k': { GdkPixbuf* pb_rotate = gdk_pixbuf_rotate_simple(q->pb, GDK_PIXBUF_ROTATE_CLOCKWISE); g_object_unref(q->pb); q->pb = pb_rotate; snprintf(infotext, sizeof infotext, "(Rotated right)"); swap(&q->orig_w, &q->orig_h); swap(&q->win_w, &q->win_h); check_size(q, FALSE); correct_image_position(q); update_image(q, REDRAW); break; } /* Rotate left */ case 'l': { GdkPixbuf* pb_rotate = gdk_pixbuf_rotate_simple(q->pb, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE); g_object_unref(q->pb); q->pb = pb_rotate; snprintf(infotext, sizeof infotext, "(Rotated left)"); swap(&q->orig_w, &q->orig_h); swap(&q->win_w, &q->win_h); check_size(q, FALSE); correct_image_position(q); update_image(q, REDRAW); break; } /* Center image on background */ case 'x': to_root=1; set_desktop_image(q); snprintf(infotext, sizeof infotext, "(Centered image on background)"); update_image(q, MIN_REDRAW); to_root=0; break; /* Tile image on background */ case 'y': to_root_t=1; set_desktop_image(q); snprintf(infotext, sizeof infotext, "(Tiled image on background)"); update_image(q, MIN_REDRAW); to_root_t=0; break; case 'z': to_root_s=1; set_desktop_image(q); snprintf(infotext, sizeof infotext, "(Stretched image on background)"); update_image(q, MIN_REDRAW); to_root_s=0; break; /* Decrease slideshow delay */ case GDK_KEY_F11: exit_slideshow = FALSE; if (delay > 1000) { delay-=1000; snprintf(infotext, sizeof infotext, "(Slideshow-Delay: %d seconds (-1)", delay/1000); update_image(q, MOVED); }else{ snprintf(infotext, sizeof infotext, "(Slideshow-Delay: can not be less than 1 second!)"); update_image(q, MOVED); } break; /* Show magnifying window */ case '<': // [lc] if (!fullscreen) { magnify ^= 1; int xcur, ycur; if (!magnify) { gdk_window_hide(magnify_img.win); } else { setup_magnify(q, &magnify_img); gdk_window_get_pointer(q->win, &xcur, &ycur, NULL); update_magnify(q, &magnify_img, REDRAW, xcur, ycur); // [lc] qiv_disable_mouse_events(q); } } break; /* Increase slideshow delay */ case GDK_KEY_F12: exit_slideshow = FALSE; delay+=1000; snprintf(infotext, sizeof infotext, "(Slideshow-Delay: %d seconds (+1)", delay/1000); update_image(q,MOVED); break; case 'X': if(num_monitors > 1) { q->mon_id = (q->mon_id + 1) % num_monitors; qiv_load_image(q); } break; case ',': if(fullscreen) { disable_grab ^= 1; snprintf(infotext, sizeof infotext, "(grab %s)", (disable_grab ? "off" : "on")); } else { do_grab ^= 1; snprintf(infotext, sizeof infotext, "(grab %s)", (do_grab ? "on" : "off")); } if((!fullscreen && do_grab) || (fullscreen && !disable_grab)) { #if GDK_MAJOR_VERSION < 3 gdk_pointer_grab(q->win, FALSE, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK, NULL, NULL, CurrentTime); gdk_keyboard_grab(q->win, FALSE, CurrentTime); #else GdkDisplay* display = gdk_display_get_default(); GdkDeviceManager* device_manager = gdk_display_get_device_manager(display); GdkDevice* pointer = gdk_device_manager_get_client_pointer(device_manager); gdk_device_grab(pointer, q->win, GDK_OWNERSHIP_NONE, FALSE, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK, NULL, CurrentTime); GdkDevice* keyboard = gdk_device_get_associated_device(pointer); gdk_device_grab(keyboard, q->win, GDK_OWNERSHIP_NONE, FALSE, FALSE, NULL, CurrentTime); #endif } else { gdk_pointer_ungrab(CurrentTime); gdk_keyboard_ungrab(CurrentTime); } update_image(q, MIN_REDRAW); break; /* run qiv-command */ case '^': // special command with options { extcommand =1; jidx = 0; jcmd[jidx++]=*(ev->key.string); jcmd[jidx] = '\0'; qiv_display_text_window(q, "(Sending Command)", mess, "Press to send, to abort"); // [lc] } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'D': #ifndef HAVE_EXIF case 'E': #endif case 'F': case 'H': case 'K': case 'L': case 'M': case 'n': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'Y': case 'Z': { int numlines = 0; const char **lines; run_command(q, ev->key.string, image_names[image_idx], &numlines, &lines); if (lines && numlines) qiv_display_text_window(q, "(Command output)", lines, "Push any key..."); } break; default: exit_slideshow = FALSE; break; } } break; } default: break; } if (exit_slideshow) { slide=0; dpms_enable(); } } qiv-3.0.1/Makefile.Solaris0000664000175000001440000001315414774332451014257 0ustar andyusers############################################################################## # Solaris Makefile for qiv - Quick Image Viewer - http://qiv.spiegl.de/ # User Options ############################################################################# # Directory where qiv will be installed under. PREFIX = /usr/local # Fonts to use for statusbar and comments STATUSBAR_FONT = "fixed" COMMENT_FONT = "fixed" ARTIST_FONT = "Monospace 10" # Cursor to use on qiv windows - see # /usr/X11R6/include/X11/cursorfont.h for more choices. CURSOR = 84 # Should image be centered on screen by default? 1=yes, 0=no. CENTER = 1 # Should images be filtered by extension? 1=yes, 0=no. FILTER = 1 # This sets the file extentions to filter on (other file types will be # skipped.) It should reflect whatever is compiled into imlib. # The latest version of imlib has removed imagemagick fallback support, # so some extensions (XBM TGA) have been removed. EXTNS = GIF TIFF XPM PNG PPM PNM PGM PCX BMP EIM JPEG SVG WMF ICO # Comment this line out if your system doesn't have getopt_long(). #GETOPT_LONG = -DHAVE_GETOPT_LONG # This program will be run on the manual page after it is installed. # If you don't want to compress the manpage, change it to 'true'. COMPRESS_PROG = gzip -9f # Comment this line out if your system doesn't have lcms2 installed # (for minimal Color Management support) LCMS = -DSUPPORT_LCMS # Comment this line out if you do not want to use libmagic to # identify if a file is an image MAGIC = -DHAVE_MAGIC # Uncomment if libmagic is installed in a non standard place #MAGIC_PREFIX = /data/magictools # Comment this line out if you do not want to use libexif to # display the exif contents of a jpg EXIF = -DHAVE_EXIF ###################################################################### # Variables and Rules # Do not edit below here! ###################################################################### ifeq ($(origin CC),default) CC = gcc endif CFLAGS = -O2 -Wall -fomit-frame-pointer -finline-functions \ -fcaller-saves -ffast-math -fno-strength-reduce \ -fthread-jumps #-march=pentium #-DSTAT_MACROS_BROKEN INCLUDES := $(shell pkg-config --cflags gdk-2.0 imlib2) LIBS := $(shell pkg-config --libs gdk-2.0 imlib2) -lX11 lXext -lgio-2.0 # [as] thinks that this is not portable enough: # [lc] I use a virtual screen of 1600x1200, and the resolution is 1024x768, # so I changed (in main.c) how screen_[x,y] is obtained; it seems that gtk # 1.2 cannot give the geometry of viewport, so I borrowed from the source # of xvidtune the code for calling XF86VidModeGetModeLine, this requires # the linking option -lXxf86vm. #LIBS += -lXxf86vm PROGRAM = qiv OBJS = main.o image.o event.o options.o utils.o xmalloc.o HEADERS = qiv.h DEFINES = $(patsubst %,-DEXTN_%, $(EXTNS)) \ $(GETOPT_LONG) \ -DSTATUSBAR_FONT='$(STATUSBAR_FONT)' \ -DCOMMENT_FONT='$(COMMENT_FONT)' \ -DARTIST_FONT='$(ARTIST_FONT)' \ -DCENTER=$(CENTER) \ -DFILTER=$(FILTER) \ -DCURSOR=$(CURSOR) \ $(MAGIC) \ $(EXIF) \ $(LCMS) ifndef GETOPT_LONG OBJS += lib/getopt.o lib/getopt1.o OBJS_G += lib/getopt.g lib/getopt1.g endif ifdef LCMS INCLUDES += $(shell pkg-config --cflags lcms2) LIBS += $(shell pkg-config --libs lcms2) -ljpeg -ltiff endif ifdef EXIF INCLUDES += $(shell pkg-config --cflags libexif) LIBS += $(shell pkg-config --libs libexif) endif ifdef MAGIC ifdef MAGIC_PREFIX INCLUDES += -I$(MAGIC_PREFIX)/include LIBS += -L$(MAGIC_PREFIX)/lib endif LIBS += -lmagic -lz endif PROGRAM_G = qiv-g OBJS_G = $(OBJS:.o=.g) DEFINES_G = $(DEFINES) -DDEBUG ###################################################################### all: $(PROGRAM) $(PROGRAM): $(OBJS) $(CC) $(CFLAGS) $(DEFINES) $(OBJS) $(LIBS) -o $(PROGRAM) $(OBJS): %.o: %.c $(HEADERS) $(CC) -c $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $@ main.o: main.h ###################################################################### debug: $(PROGRAM_G) $(PROGRAM_G): $(OBJS_G) $(CC) -g $(CFLAGS) $(DEFINES_G) $(LIBS) $(OBJS_G) -o $(PROGRAM_G) $(OBJS_G): %.g: %.c $(HEADERS) $(CC) -c -g $(CFLAGS) $(DEFINES_G) $(INCLUDES) $< -o $@ ###################################################################### clean : @echo "Cleaning up..." rm -f $(OBJS) $(OBJS_G) distclean : clean rm -f $(PROGRAM) $(PROGRAM_G) install: $(PROGRAM) @echo "Installing QIV..." @if [ ! -d $(PREFIX)/bin ]; then \ install -d -m 0755 $(PREFIX)/bin; \ echo install -d -m 0755 $(PREFIX)/bin; \ fi install -s -m 0755 $(PROGRAM) $(PREFIX)/bin @if [ ! -d $(PREFIX)/man/man1 ]; then \ echo install -d -m 0755 $(PREFIX)/man/man1; \ install -d -m 0755 $(PREFIX)/man/man1; \ fi install -m 0644 $(PROGRAM).1 $(PREFIX)/man/man1 $(COMPRESS_PROG) $(PREFIX)/man/man1/$(PROGRAM).1 install -D -m 0644 qiv.png $(PREFIX)/share/pixmaps/qiv.png install -D -m 0644 qiv.desktop $(PREFIX)/share/applications/qiv.desktop @if [ ! -e $(PREFIX)/share/pixmaps ]; then \ echo install -d -m 0755 $(PREFIX)/share/pixmaps; \ install -d -m 0755 $(PREFIX)/share/pixmaps; \ fi install -m 0644 qiv.png $(PREFIX)/share/pixmaps/qiv.png @if [ ! -e $(PREFIX)/share/applications ]; then \ echo install -d -m 0755 $(PREFIX)/share/applications; \ install -d -m 0755 $(PREFIX)/share/applications; \ fi install -m 0644 qiv.desktop $(PREFIX)/share/applications/qiv.desktop @if ./qiv -f ./intro.jpg ; \ then echo "-- Test Passed --" ; \ else echo "-- Test Failed --" ; \ fi @echo "\nDont forget to look into the \"qiv-command\" file and install it!\n-> cp qiv-command.example $(PREFIX)/bin/qiv-command\n\n" # the end... ;-) qiv-3.0.1/utils.c0000664000175000001440000007536414774332451012523 0ustar andyusers/* Module : utils.c Purpose : Various utilities for qiv More : see qiv README Policy : GNU GPL Homepage : http://qiv.spiegl.de/ Original : http://www.klografx.net/qiv/ */ #define _DEFAULT_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_EXIF #include #endif #include "qiv.h" #include "xmalloc.h" #ifdef STAT_MACROS_BROKEN #undef S_ISDIR #endif #if !defined(S_ISDIR) && defined(S_IFDIR) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif /* move current image to .qiv-trash */ int move2trash() { char *ptr, *ptr2, *filename = image_names[image_idx]; char trashfile[FILENAME_LEN], path_result[PATH_MAX]; int i; if (readonly) return 0; if(!(ptr = strrchr(filename, '/'))) { /* search rightmost slash */ /* no slash in filename */ strncpy(path_result, filename, PATH_MAX); /* move file to TRASH_DIR/filename */ snprintf(trashfile, sizeof trashfile, "%s/%s", TRASH_DIR, path_result); } else { /* find full path to file */ *ptr = 0; if(!realpath(filename,path_result)) { g_print("Error: realpath failure while moving file to trash\a\n"); *ptr = '/'; return 1; } /* move file to fullpath/TRASH_DIR/filename */ snprintf(trashfile, sizeof trashfile, "%s/%s/%s", path_result, TRASH_DIR, ptr+1); strncat(path_result, "/", PATH_MAX - strlen(path_result) ); strncat(path_result, ptr + 1, PATH_MAX - strlen(path_result) ); *ptr = '/'; } #ifdef DEBUG g_print("*** trashfile: '%s'\n",trashfile); #endif ptr = ptr2 = trashfile; if(trashfile[0] == '/') { /* filename starts with a slash? */ ptr += 1; } while((ptr = strchr(ptr,'/'))) { *ptr = '\0'; if(access(ptr2,F_OK)) { if(mkdir(ptr2,0700)) { g_print("Error: Could not make directory '%s'\a\n",ptr2); return 1; } } *ptr = '/'; ptr += 1; } unlink(trashfile); /* Just in case it already exists... */ if(rename(filename,trashfile)) { g_print("Error: Could not rename '%s' to '%s'\a\n",filename,trashfile); return 1; } else { qiv_deletedfile *del; if (!deleted_files) deleted_files = (qiv_deletedfile*)xcalloc(MAX_DELETE,sizeof *deleted_files); del = &deleted_files[delete_idx++]; if (delete_idx == MAX_DELETE) delete_idx = 0; if (del->filename) free(del->trashfile); del->filename = filename; del->trashfile = strdup(trashfile); del->pos = image_idx; --images; for(i=image_idx;imessage); g_error_free(del_error); ret=1; } g_object_unref(del_file); return ret; } /* copy current image to SELECTDIR */ int copy2select() { char *ptr, *filename = image_names[image_idx]; char dstfile[FILENAME_LEN], dstfilebak[FILENAME_LEN], tmp[FILENAME_LEN], buf[BUFSIZ]; int fdi, fdo, n, n2; /* try to create something; if select_dir doesn't exist, create one */ snprintf(dstfile, sizeof dstfile, "%s/.qiv-select", select_dir); if((n = open(dstfile, O_CREAT, 0666)) == -1) { switch(errno) { case EEXIST: unlink(dstfile); break; case ENOTDIR: case ENOENT: if(mkdir(select_dir, 0777) == -1) { g_print("*** Error: Cannot create select_dir '%s': %s\a\n", select_dir, strerror(errno)); return -1; } break; default: g_print("*** Error: Cannot open select_dir '%s': %s\a\n", select_dir, strerror(errno)); return -1; } } else { close(n); unlink(dstfile); } if((ptr = strrchr(filename, '/')) != NULL) { /* search rightmost slash */ ptr++; } else { ptr = filename; } snprintf(dstfile, sizeof dstfile, "%s/%s", select_dir, ptr); #ifdef DEBUG g_print("*** selectfile: '%s'\n",dstfile); #endif ptr = dstfile; /* Just in case the file already exists... */ /* unlink(dstfile); */ snprintf(dstfilebak, sizeof dstfilebak, "%s", dstfile); while ((n2 = open(dstfilebak, O_RDONLY)) != -1) { close(n2); snprintf(tmp, sizeof dstfilebak, "%s.bak", dstfilebak); strncpy(dstfilebak, tmp, sizeof dstfilebak); } if ( strncmp(dstfile, dstfilebak, sizeof dstfile) != 0 ) { #ifdef DEBUG g_print("*** renaming: '%s' to '%s'\n",dstfile,dstfilebak); #endif rename(dstfile, dstfilebak); } fdi = open(filename, O_RDONLY); fdo = open(dstfile, O_CREAT | O_WRONLY, 0666); if(fdi == -1 || fdo == -1) { g_print("*** Error: Could not copy file: '%s'\a\n", strerror(errno)); } while((n = read(fdi, buf, BUFSIZ)) > 0) write(fdo, buf, n); close(fdi); close(fdo); return 0; } /* move the last deleted image out of the delete list */ int undelete_image() { int i; qiv_deletedfile *del; char *ptr; if (readonly) return 0; if (!deleted_files) { g_print("Error: nothing to undelete\a\n"); return 1; } if (--delete_idx < 0) delete_idx = MAX_DELETE - 1; del = &deleted_files[delete_idx]; if (!del->filename) { g_print("Error: nothing to undelete\a\n"); return 1; } if (rename(del->trashfile,del->filename) < 0) { g_print("Error: undelete_image '%s' failed\a\n", del->filename); del->filename = NULL; free(del->trashfile); return 1; } /* unlink TRASH_DIR if empty */ ptr = del->trashfile; /* the path without the filename is the TRASH_DIR */ ptr = strrchr(ptr,'/'); *ptr = '\0'; if(rmdir(del->trashfile)) { /* we can't delete the TRASH_DIR because there are still files */ } *ptr = '/'; image_idx = del->pos; for(i=images;--i>=image_idx;) { image_names[i+1] = image_names[i]; } images++; image_names[image_idx] = del->filename; del->filename = NULL; free(del->trashfile); return 0; } #define MAXOUTPUTBUFFER 16384 #define MAXLINES 100 /* run a command ... */ void run_command(qiv_image *q, char *n, char *filename, int *numlines, const char ***output) { static char nr[100]; static char *buffer = 0; static const char *lines[MAXLINES + 1]; int pipe_stdout[2]; int pid; char *newfilename; int i; struct stat before, after; stat(filename, &before); if (!buffer) buffer = xmalloc(MAXOUTPUTBUFFER + 1); *numlines = 0; *output = lines; snprintf(infotext, sizeof infotext, "Running: 'qiv-command %s %s'", n, filename); snprintf(nr, sizeof nr, "%s", n); /* Use some pipes for stdout and stderr */ if (pipe(pipe_stdout) < 0) { perror("pipe"); return; } pid = fork(); if (pid == 0) { /* Child */ dup2(pipe_stdout[1], 1); dup2(pipe_stdout[1], 2); close(pipe_stdout[1]); execlp("qiv-command", "qiv-command", nr, filename, NULL); perror("Error calling qiv-command"); abort(); } else if (pid > 0) { /* parent */ int len = 0; char *p = buffer; gboolean finished = FALSE; close(pipe_stdout[1]); do { char *s = p, *q; finished = waitpid(pid, 0, WNOHANG) > 0; len = read(pipe_stdout[0], s, MAXOUTPUTBUFFER - (s - buffer)); if (len < 0 || (finished && len == 0)) break; s[len] = '\0'; /* Process the buffer into lines */ for (; *numlines < MAXLINES && p < s + len; ) { lines[(*numlines)++] = p; /* Find the end of the line */ q = strchr(p, '\n'); if (!q) break; *q = '\0'; p = q + 1; } } while (len > 0); lines[(*numlines)] = 0; if (!finished) waitpid(pid, 0, 0); close(pipe_stdout[0]); } else { perror("fork"); return; } /* Check for special keyword "NEWNAME=" in first line * indicating that the filename has changed */ if ( lines[0] && strncmp(lines[0], "NEWNAME=", 8) == 0 ) { newfilename = strdup(lines[0]); newfilename += 8; #ifdef DEBUG g_print("*** filename has changed from: '%s' to '%s'\n", image_names[image_idx], newfilename); #endif image_names[image_idx] = strdup(newfilename); filename = strdup(newfilename); /* delete this line from the output */ (*numlines)--; lines[0] = 0; for (i = 0; i < *numlines; i++) { lines[i] = lines[i+1]; } } stat(filename, &after); /* If image modified reload, otherwise redraw */ if (before.st_size == after.st_size && before.st_ctime == after.st_ctime && before.st_mtime == after.st_mtime) update_image(q, MIN_REDRAW); else qiv_load_image(q); } /* This routine jumps x images forward or backward or directly to image x Enter jf10\n ... jumps 10 images forward Enter jb5\n ... jumps 5 images backward Enter jt15\n ... jumps to image 15 */ void jump2image(char *cmd) { int direction = 0; int x; #ifdef DEBUG g_print("*** starting jump2image function: '%s'\n", cmd); #endif if(cmd[0] == 'f' || cmd[0] == 'F') direction = 1; else if(cmd[0] == 'b' || cmd[0] == 'B') direction = -1; else if(!(cmd[0] == 't' || cmd[0] == 'T')) return; /* get number of images to jump or image to jump to */ x = atoi(cmd+1); if (direction == 1) { if ((image_idx + x) > (images-1)) image_idx = images-1; else image_idx += x; } else if (direction == -1) { if ((image_idx - x) < 0) image_idx = 0; else image_idx -= x; } else { if (x > images || x < 1) return; else image_idx = x-1; } #ifdef DEBUG g_print("*** end of jump2image function\n"); #endif } void finish(int sig) { gdk_pointer_ungrab(CurrentTime); gdk_keyboard_ungrab(CurrentTime); dpms_enable(); exit(0); } /* Update selected image index image_idx Direction determines if the next or the previous image is selected. */ void next_image(int direction) { static int last_modif = 1; /* Delta of last change of index of image */ if (!direction) direction = last_modif; else last_modif = direction; if (random_order) image_idx = get_random(random_replace, images, direction); else { image_idx = (image_idx + direction) % images; if (image_idx < 0) image_idx += images; else if (cycle && image_idx == 0) qiv_exit(0); } } int checked_atoi (const char *s) { char *endptr; int num = strtol(s, &endptr, 0); if (endptr == s || *endptr != '\0') { g_print("Error: %s is not a valid number.\n", s); exit(1); } return num; } float checked_atof (const char *s) { char *endptr; float num = strtof(s, &endptr); if (endptr == s || *endptr != '\0') { g_print("Error: %s is not a valid floating point number.\n", s); exit(1); } return num; } void usage(char *name, int exit_status) { g_print("qiv (Quick Image Viewer) v%s\n" "Usage: qiv [options] files ...\n" "See 'man qiv' or type 'qiv --help' for options.\n", VERSION); exit(exit_status); } void show_help(char *name, int exit_status) { int i; g_print("qiv (Quick Image Viewer) v%s\n" "Usage: qiv [options] files ...\n\n", VERSION); g_print( "General options:\n" " --file, -F x Read file names from text file x or stdin\n" " --bg_color, -o x Set root background color to x\n" " --brightness, -b x Set brightness to x (-32..32)\n" " --browse, -B Scan directory of file for browsing\n" " --center, -e Disable window centering\n" " --contrast, -c x Set contrast to x (-32..32)\n" " --cycle, -C do not cycle after last image\n" " --display x Open qiv window on display x\n" " --do_grab, -a Grab the pointer in windowed mode\n" " --disable_grab, -G Disable pointer/kbd grab in fullscreen mode\n" " --fixed_width, -w x Window with fixed width x\n" " --fixed_zoom, -W x Window with fixed zoom factor (percentage x)\n" " --highDPIfactor FLOAT Resize factor to compensate for high (or also low) DPI screens\n" " --fullscreen, -f Use fullscreen window on start-up\n" " --gamma, -g x Set gamma to x (-32..32)\n" " --help, -h This help screen\n" " --ignore_path_sort, -P Sort filenames by the name only\n" " --readonly, -R Disable the deletion feature\n" " --maxpect, -m Zoom to screen size and preserve aspect ratio\n" " --merged_case_sort, -M Sort filenames with AaBbCc... alpha order\n" " --mtime_sort, -K Sort files by their modification time\n" " --no_filter, -n Do not filter images by extension\n" " --no_statusbar, -i Disable statusbar\n" " --statusbar, -I Enable statusbar\n" " --showJPEGcomments, -J Enable display of JPEG comments\n" " --showArtistName, -E Enable display of artist (author) name\n" " --artist_ignore x Do NOT show artist name if it is equal to x\n" " --no_sort, -D Do not apply any sorting to the list of files\n" " --numeric_sort, -N Sort filenames with numbers intuitively\n" " --root, -x Set centered desktop background and exit\n" " --root_t, -y Set tiled desktop background and exit\n" " --root_s, -z Set stretched desktop background and exit\n" " --scale_down, -t Shrink image(s) larger than the screen to fit\n" " --trashbin Use users trash bin instead of .qiv_trash when deleting\n" " (undelete key will not work in that case)\n" " --transparency, -p Enable transparency for transparent images\n" " --watch, -T Reload the image if it has changed on disk\n" " --recursivedir, -u Recursively include all files\n" " --followlinks, -L Follow symlinks to directories (requires --recursivedir)\n" " --select_dir, -A x Store the selected files in dir x (default is .qiv-select)\n" #if GDK_PIXBUF_MINOR >= 12 " --autorotate, -l Do NOT autorotate JPEGs according to EXIF rotation tag\n" #endif " --rotate, -q x Rotate 90(x=1),180(x=2),270(x=3) degrees clockwise (11 & 13 for conditional)\n" " --xineramascreen, -X x Use monitor x as preferred screen\n" #ifdef SUPPORT_LCMS " --source_profile, -Y x Use color profile file x as source profile for all images\n" " --display_profile,-Z x Use color profile file x as display profile for all images\n" #endif " --vikeys Enable movement with h/j/k/l, vi-style\n" " (HJKL will do what hjkl previously did)\n" " --version, -v Print version information and exit\n" "\n" "Slideshow options:\n" "This can also be used for the desktop background (x/y/z)\n" " --slide, -s Start slideshow immediately\n" " --random, -r Random order\n" " --shuffle, -S Shuffled order\n" " --delay, -d x Wait x seconds between images [default=%d]\n" "\n" "Keys:\n", SLIDE_DELAY/1000); /* skip header and blank line */ for (i=0; helpkeys[i]; i++) g_print(" %s\n", helpkeys[i]); g_print("\nValid image extensions:\nUse --no_filter/-n to disable"); for (i=0; image_extensions[i]; i++) g_print("%s%s", (i%8) ? " " : "\n ", image_extensions[i]); g_print("\n\n"); g_print("Homepage: http://qiv.spiegl.de/\n" "Please mail bug reports and comments to Andy Spiegl \n"); exit(exit_status); } /* returns a random number from the integers 0..num-1, either with replacement (replace=1) or without replacement (replace=0) */ int get_random(int replace, int num, int direction) { static int index = -1; static int *rindices = NULL; /* the array of random intgers */ static int rsize; int n,m,p,q; if (!rindices) rindices = (int *) xmalloc((unsigned) max_rand_num*sizeof(int)); if (rsize != num) { rsize = num; index = -1; } if (index < 0) /* no more indices left in this cycle. Build a new */ { /* array of random numbers, by not sorting on random keys */ index = num-1; for (m=0;m is true, * else just reads directory */ int rreaddir(const char *dirname, int recursive) { DIR *d; struct dirent *entry; char cdirname[FILENAME_LEN], name[FILENAME_LEN]; struct stat sb; int before_count = images; strncpy(cdirname, dirname, sizeof cdirname); cdirname[FILENAME_LEN-1] = '\0'; if (!(d = opendir(cdirname))) return -1; while ((entry = readdir(d)) != NULL) { if (strcmp(entry->d_name,".") == 0 || strcmp(entry->d_name,"..") == 0 || strcmp(entry->d_name,TRASH_DIR) == 0) continue; snprintf(name, sizeof name, "%s/%s", cdirname, entry->d_name); if ((followlinks ? stat(name, &sb) : lstat(name, &sb)) >= 0) { if (S_ISDIR(sb.st_mode)) { if (!recursive) continue; rreaddir(name,1); } else { if (images >= max_image_cnt) { max_image_cnt += 8192; if (!image_names) image_names = (char**)xmalloc(max_image_cnt * sizeof(char*)); else image_names = (char**)xrealloc(image_names,max_image_cnt*sizeof(char*)); } image_names[images++] = strdup(name); } } } closedir(d); return images - before_count; } /* Read image filenames from a file */ int rreadfile(const char *filename) { FILE *fp; struct stat sb; int before_count = images; if (strcmp(filename,"-")) { fp = fopen(filename, "r"); if(!fp) return -1; } else fp = stdin; if (!images) { max_image_cnt = 8192; image_names = (char**)xmalloc(max_image_cnt * sizeof(char*)); } while (1) { char line[ BUFSIZ ]; size_t linelen; if (fgets(line, sizeof(line), fp) == NULL ) { if (ferror(fp)) g_print("Error while reading %s: %s\n", filename, strerror(errno)); fclose(fp); break; } linelen = strlen(line) -1; if (line[linelen] == '\n') line[linelen--] = '\0'; if (line[linelen] == '\r') line[linelen--] = '\0'; if (stat(line, &sb) >= 0 && S_ISDIR(sb.st_mode)) rreaddir(line,1); else { if (images >= max_image_cnt) { max_image_cnt += 8192; image_names = (char**)xrealloc(image_names,max_image_cnt*sizeof(char*)); } image_names[images++] = strdup(line); } } return images - before_count; } /* gboolean color_alloc(const char *name, GdkColor *color) { gboolean result; result = gdk_color_parse(name, color); if (!result) { fprintf(stderr, "qiv: can't parse color '%s'\n", name); name = "black"; } result = gdk_colormap_alloc_color(cmap, color, FALSE, TRUE); if (!result) { fprintf(stderr, "qiv: can't alloc color '%s'\n", name); color->pixel = 0; } return result; } */ void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } /* rounding a float to an int */ int myround( double a ) { return( (a-(int)a > 0.5) ? (int)a+1 : (int)a); } /* File watcher, an idle thread checking whether the loaded file has changed */ gboolean qiv_watch_file (gpointer data) { struct stat statbuf; qiv_image *q=data; if(!watch_file) return FALSE; stat(image_names[image_idx], &statbuf); if(current_mtime!=statbuf.st_mtime && statbuf.st_size){ if(time(NULL)-statbuf.st_mtime > 0) { reload_image(q); check_size(q, FALSE); update_image(q, REDRAW); } } return TRUE; } int find_image(int images, char **image_names, char *name) { int i; for (i=0; inext) { if(strncmp(icc_string, (const char *)marker->data, 11)==0) { if(i==0) { seq_max = marker->data[icc_string_len+1]; tag_length = calloc(seq_max, sizeof(short)); tag_ptr = calloc(seq_max, sizeof(char *)); } seq_id = marker->data[icc_string_len]; seq_size = marker->data_length - icc_offset; // workaround: if there is only one ICC header, ignore a wrong value by setting it to 1 if((seq_max == 1) && (seq_id != 1)){ printf("qiv warning: fixing incorrect ICC chunk ID in %s\n", filename); seq_id = 1; } // Sanity checks // id runs from 1 to max ID, max ID must stay same for all ICC tags, size of ICC data > 0 if((seq_id < 1) || (seq_id > seq_max) || (seq_size <= 0) || (seq_max != marker->data[icc_string_len+1])){ printf("qiv warning: %s contains illegal ICC tag\n", filename); free(tag_length); free(tag_ptr); return NULL; } // we already had this ID if(tag_length[seq_id-1]){ printf("qiv warning: %s contains duplicate ICC sequence number\n", filename); free(tag_length); free(tag_ptr); return NULL; } tag_length[seq_id-1] = seq_size; tag_ptr[seq_id-1] = marker->data + icc_offset; i++; } /* copy jpeg comment here to be printed out when EXIF data or comment window is displayed. */ else if(marker->marker==JPEG_COM) { comment=calloc(1+marker->data_length,1); if(comment==NULL) return NULL; strncpy(comment, (char *) marker->data, marker->data_length); /* simulate perl's chomp */ int len = strlen(comment); while (isspace(comment[len-1])) { comment[len-1] = 0; if(--len==0) break; } } } if(i==0) { /* No icc markers found */ return NULL; } else if(i != seq_max){ /* icc markers are missing */ printf("qiv warning: %s has incomplete ICC profile\n", filename); free(tag_length); free(tag_ptr); return NULL; } else { /* Sort the markers and copy them together */ for(j=0; j< i; j++) { length+= tag_length[j]; } icc_ptr = malloc(length+sizeof(length)); if(icc_ptr==NULL) return NULL; *(unsigned int *)icc_ptr=length; length=0; for(j=0; j< i; j++) { memcpy(icc_ptr+length+sizeof(length), tag_ptr[j], tag_length[j]); length+= tag_length[j]; } free(tag_ptr); free(tag_length); } jpeg_destroy_decompress(&cinfo); return icc_ptr; } /* is pic a tiff?*/ else if((pic_tst[0] == pic_tst[1]) && ((pic_tst[0] == 0x49)||(pic_tst[0] == 0x4d)) && (pic_tst[2] == 0x2a) && (pic_tst[3] == 0x00)) { uint16_t count; unsigned char *data; fclose(infile); if((tiff_image = TIFFOpen(filename, "r")) == NULL){ fprintf(stderr, "Could not open incoming image\n"); return NULL; } if (TIFFGetField(tiff_image, TIFFTAG_ICCPROFILE, &count, &data)) { length = count; icc_ptr = malloc(length+sizeof(length)); *(unsigned int *)icc_ptr=length; memcpy(icc_ptr+sizeof(length), data, length); } TIFFClose(tiff_image); return icc_ptr; } fclose(infile); return NULL; } #endif #ifdef HAVE_EXIF char **get_exif_values(char *filename) { ExifData *ed; ExifEntry *entry; int i,j; char *line; char **exif_lines=NULL; char buffer[256]; /* displayed exif tags, when available */ struct { ExifTag tag; ExifIfd ifd; } tags[] = { {EXIF_TAG_ARTIST, EXIF_IFD_0}, {EXIF_TAG_MAKE, EXIF_IFD_0}, {EXIF_TAG_MODEL, EXIF_IFD_0}, {EXIF_TAG_DOCUMENT_NAME, EXIF_IFD_0}, {EXIF_TAG_PIXEL_X_DIMENSION , EXIF_IFD_EXIF}, {EXIF_TAG_PIXEL_Y_DIMENSION , EXIF_IFD_EXIF}, {EXIF_TAG_SOFTWARE, EXIF_IFD_0}, {EXIF_TAG_DATE_TIME, EXIF_IFD_0}, {EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_IFD_EXIF}, {EXIF_TAG_ORIENTATION, EXIF_IFD_0}, {EXIF_TAG_JPEG_PROC, EXIF_IFD_1}, {EXIF_TAG_FLASH, EXIF_IFD_EXIF}, {EXIF_TAG_EXPOSURE_TIME, EXIF_IFD_EXIF}, {EXIF_TAG_ISO_SPEED_RATINGS, EXIF_IFD_EXIF}, {EXIF_TAG_APERTURE_VALUE, EXIF_IFD_EXIF}, {EXIF_TAG_FOCAL_LENGTH, EXIF_IFD_EXIF}, {EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, EXIF_IFD_EXIF}, {EXIF_TAG_SHUTTER_SPEED_VALUE, EXIF_IFD_EXIF}, {EXIF_TAG_SUBJECT_DISTANCE, EXIF_IFD_EXIF}, {EXIF_TAG_METERING_MODE, EXIF_IFD_EXIF}, {EXIF_TAG_EXPOSURE_MODE, EXIF_IFD_EXIF}, {EXIF_TAG_SENSING_METHOD, EXIF_IFD_EXIF}, {EXIF_TAG_WHITE_BALANCE, EXIF_IFD_EXIF}, {EXIF_TAG_GAIN_CONTROL, EXIF_IFD_EXIF}, {EXIF_TAG_COLOR_SPACE, EXIF_IFD_EXIF}, {EXIF_TAG_CONTRAST, EXIF_IFD_EXIF}, {EXIF_TAG_SATURATION, EXIF_IFD_EXIF}, {EXIF_TAG_SHARPNESS, EXIF_IFD_EXIF}, {EXIF_TAG_DIGITAL_ZOOM_RATIO, EXIF_IFD_EXIF} }; ExifTag gps_tags[] = { EXIF_TAG_GPS_LATITUDE, EXIF_TAG_GPS_LATITUDE_REF, EXIF_TAG_GPS_LONGITUDE, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_TAG_GPS_ALTITUDE, EXIF_TAG_GPS_ALTITUDE }; j=0; ed = exif_data_new_from_file(filename); if(ed) { /* one too much to make sure the last one will always be NULL size of tags + gpstags(3) + extra lines(3) + 1 */ exif_lines=calloc(sizeof(tags)/sizeof(tags[0]),sizeof(char*)+3+3+1); for(i=0; i < sizeof(tags)/sizeof(tags[0]); i++) { entry=exif_content_get_entry( ed->ifd[tags[i].ifd], tags[i].tag); if(entry) { line=malloc(256); exif_entry_get_value (entry, buffer, 255); snprintf(line, 255, "%-21s: %s\n", exif_tag_get_name_in_ifd(tags[i].tag,tags[i].ifd), buffer); exif_lines[j]=line; j++; } } for(i=0; i < 6; i+=2) { entry=exif_content_get_entry( ed->ifd[EXIF_IFD_GPS], gps_tags[i]); if(entry) { line=malloc(256); exif_entry_get_value (entry, buffer, 255); if((entry=exif_content_get_entry( ed->ifd[EXIF_IFD_GPS], i+1))) { int len=strlen(buffer); if(len < 254) { buffer[len]=0x20; exif_entry_get_value(entry, buffer+len+1, 254-len); } } snprintf(line, 255, "%-21s: %s\n", exif_tag_get_name_in_ifd(gps_tags[i], EXIF_IFD_GPS), buffer); exif_lines[j]=line; j++; } } } if(j==0) { free(exif_lines); return NULL; } line=malloc(64); snprintf(line, 63, "%-21s: %i Bytes\n", "FileSize", (int)file_size); exif_lines[j++]=line; if(jpeg_prog) { line=malloc(64); snprintf(line, 63, "%-21s: %s\n", "JpegProcess", "Progressive"); exif_lines[j++]=line; } if(comment) { line=malloc(256); snprintf(line, 255, "%-21s: %s\n", "Comment", comment); exif_lines[j++]=line; } return exif_lines; } char *get_exif_artist(char *filename) { ExifData *ed; ExifEntry *entry; char *exif_artist=NULL; char buffer[255]; ed = exif_data_new_from_file(filename); if(ed) { entry=exif_content_get_entry( ed->ifd[ EXIF_IFD_0], EXIF_TAG_ARTIST ); if(entry) { exif_artist=malloc(255); exif_entry_get_value (entry, buffer, 255); snprintf(exif_artist, 255, "%s", buffer); } } // printf("DEBUG: Artist: %s\n", exif_artist); return exif_artist; } #endif /* The state of DPMS is checked at startup of qiv. If the display is DPMS capable and DPMS is activated, qiv disables it during a slideshow to prevent the screen from blanking. */ BOOL dpms_enabled = 0; void dpms_check() { int not_needed; Display * disp = gdk_x11_display_get_xdisplay(gdk_display_get_default()); CARD16 power_level; if(DPMSQueryExtension(disp, ¬_needed, ¬_needed)) { if(DPMSCapable(disp)) { DPMSInfo(disp, &power_level, &dpms_enabled); } } } void dpms_enable() { if(dpms_enabled) { DPMSEnable(gdk_x11_display_get_xdisplay(gdk_display_get_default())); } } void dpms_disable() { if(dpms_enabled) { DPMSDisable(gdk_x11_display_get_xdisplay(gdk_display_get_default())); } } qiv-3.0.1/qiv.h0000664000175000001440000001764314774332451012163 0ustar andyusers#include #include #include #include #ifdef SUPPORT_LCMS #include #include #endif /* // [as] thinks that this is not portable enough // [lc] // I use a virtual screen of 1600x1200, and the resolution is 1024x768, // so I changed how screen_[x,y] is obtained; it seems that gtk 1.2 // cannot give the geometry of viewport, so I borrowed from the source of // xvidtune the code for calling XF86VidModeGetModeLine, this requires // the linking option -lXxf86vm. #include #include // for XF86VidModeGetModeLine */ #define VERSION "3.0.1" #define VERSION_FULL "QIV - Quick Image Viewer v3.0.1 - http://qiv.spiegl.de/" #define TRASH_DIR ".qiv-trash" #define SELECT_DIR ".qiv-select" #define SLIDE_DELAY 3000 /* milliseconds */ #define IMAGE_BG "black" #define STATUSBAR_BG 0xFFB900 #define STATUSBAR_FS 8 /* default fontsize if none is given */ #define COMMENT_BG 0xDDDDDD #define COMMENT_FS 20 /* default fontsize if none is given */ #define ARTIST_BG 0xBBBBBB #define ARTIST_FS 10 /* default fontsize if none is given */ #define DEFAULT_BRIGHTNESS 256 #define DEFAULT_CONTRAST 256 #define DEFAULT_GAMMA 256 #define BUF_LEN 1024 /* FILENAME_LEN is the maximum length of any path/filename that can be * handled. MAX_DELETE determines how many items can be placed into * the kill-ring for undelete handling. */ #define FILENAME_LEN 1024 #define MAX_DELETE 1024 /* [pw] Warning: qiv uses the imlib 1.x units. Not what imlib 2 wants. */ typedef struct _qiv_color_modifier { int gamma, brightness, contrast; } qiv_color_modifier; typedef struct _qiv_image { qiv_color_modifier mod; /* Image modifier (for brightness..) */ GdkPixbuf *pb; GdkWindow *win; /* Main window for windowed and fullscreen mode */ int error; /* 1 if Imlib couldn't load image */ gint win_x, win_y, win_w, win_h, mon_id; /* window co-ordinates */ gint orig_w, orig_h; /* Size of original image in pixels */ /* These are used to work out how to redraw in fullscreen mode */ gint win_ox, win_oy, win_ow, win_oh; /* coordinates currently drawn at */ gint text_ow, text_oh; /* old size of the statusbar */ int statusbar_was_on; /* true if statusbar was visible last frame */ int exposed; /* window became visible */ int drag; /* user is currently dragging the image */ double drag_start_x, drag_start_y; /* position of cursor at drag start */ int drag_win_x, drag_win_y; /* position of win at drag start */ // char infotext[BUF_LEN]; gchar win_title[BUF_LEN]; gint text_len, text_w, text_h; gint comment_w, comment_h; gint artist_w, artist_h; } qiv_image; typedef struct _qiv_mgl { /* [pw] needs a seperate context? */ qiv_color_modifier mod; /* Image modifier (for brightness..) */ GdkWindow *win; /* window for magnify */ gint win_x, win_y, win_w, win_h; /* window coordinates */ gint frame_x, frame_y; /* UpLeft Corner of frame (titlebar included) of */ double zoom; /* main qiv_image */ // int exposed; /* window became visible */ } qiv_mgl; /* the magnifying glass [lc] */ typedef struct _qiv_deletedfile { char *filename, *trashfile; int pos; } qiv_deletedfile; extern int first; extern char infotext[BUF_LEN]; extern GMainLoop *qiv_main_loop; extern gint screen_x, screen_y; extern gint num_monitors; extern GdkScreen *screen; extern GdkRectangle *monitor; extern int images; extern char **image_names; extern int image_idx; extern int max_image_cnt; extern time_t current_mtime; extern qiv_deletedfile *deleted_files; extern int delete_idx; extern char select_dir[FILENAME_LEN]; extern PangoLayout *layout; extern PangoFontDescription *fontdesc; extern PangoFontMetrics *metrics; extern PangoLayout *layoutComment; extern PangoFontDescription *fontdescComment; extern PangoFontMetrics *metricsComment; extern char *comment; extern PangoLayout *layoutArtist; extern PangoFontDescription *fontdescArtist; extern PangoFontMetrics *metricsArtist; extern char *artist; extern gint jpeg_prog; extern off_t file_size; extern int filter; extern gint center; extern gint cycle; extern gint default_brightness; extern gint default_contrast; extern gint default_gamma; extern gint delay; extern int readonly; extern int random_order; extern int random_replace; extern int fullscreen; extern int maxpect; extern int statusbar_fullscreen; extern int statusbar_window; extern int comment_window; extern int artist_window; extern int slide; extern int scale_down; extern int recursive; extern int followlinks; extern int to_root; extern int to_root_t; extern int to_root_s; extern int transparency; extern int do_grab; extern int disable_grab; extern int max_rand_num; extern int fixed_window_size; extern int fixed_zoom_factor; extern int zoom_factor; extern int watch_file; extern int browse; extern int magnify; // [lc] extern qiv_mgl magnify_img; // [lc] extern int autorotate; extern int rotation; extern int vikeys; extern int trashbin; extern char *artist_ignore; extern float highDPIfactor; extern const char *helpstrs[], **helpkeys, *image_extensions[]; extern int user_screen; #ifdef SUPPORT_LCMS extern const char* source_profile; extern const char* display_profile; extern cmsHPROFILE h_source_profile; extern cmsHPROFILE h_display_profile; extern cmsHTRANSFORM h_cms_transform; extern int cms_transform; extern char *get_icc_profile(char *filename); #endif /* main.c */ extern void qiv_exit(int); extern void filter_images(int *images, char **image_names); /* image.c */ /* Modes for update_image */ #define REDRAW 0 #define MOVED 1 #define ZOOMED 2 #define FULL_REDRAW 3 #define MIN_REDRAW 4 extern void qiv_load_image(qiv_image *); extern void set_desktop_image(qiv_image *); extern void zoom_in(qiv_image *); extern void zoom_out(qiv_image *); extern void zoom_maxpect(qiv_image *); extern void reload_image(qiv_image *q); extern void reset_coords(qiv_image *); extern void check_size(qiv_image *, gint); extern void update_image(qiv_image *, int); extern void reset_mod(qiv_image *); extern void destroy_image(qiv_image *q); extern void center_image(qiv_image *q); extern void correct_image_position(qiv_image *q); extern void hide_cursor(qiv_image *q); extern void show_cursor(qiv_image *q); extern void setup_magnify(qiv_image *, qiv_mgl *); // [lc] extern void update_magnify(qiv_image *, qiv_mgl *,int, gint, gint); // [lc] static inline void set_cairo_color(cairo_t *cr, u_int32_t col) { cairo_set_source_rgb(cr, (col >> 16)/256.0, ((col >> 8) & 0xff)/256.0, (col & 0xff)/256.0); } /* event.c */ extern void qiv_handle_event(GdkEvent *, gpointer); /* options.c */ extern void options_read(int, char **, qiv_image *); /* utils.c */ extern int move2trash(void); extern int move2trashbin(void); extern int copy2select(void); extern int undelete_image(void); extern void jump2image(char *); extern void run_command(qiv_image *, char *, char *, int *, const char ***); extern void finish(int); extern void next_image(int); extern int checked_atoi(const char *); extern float checked_atof(const char *); extern void usage(char *, int); extern void show_help(char *, int); extern int get_random(int, int, int); extern gboolean color_alloc(const char *, GdkColor *); extern void swap(int *, int *); extern int myround(double); extern gboolean qiv_watch_file (gpointer); extern int rreaddir(const char *, int); extern int rreadfile(const char *); extern int find_image(int images, char **image_names, char *name); #ifdef HAVE_EXIF extern char **get_exif_values(char *filename); extern char *get_exif_artist(char *filename); #endif void dpms_check(); void dpms_enable(); void dpms_disable(); qiv-3.0.1/qiv.10000664000175000001440000003166714774332451012076 0ustar andyusers.\" @(#)qiv.1 -*- nroff -*- .de EX .ne 5 .if n .sp .5 .if t .sp .5 .nf .. .de EE .fi .if n .sp .5 .if t .sp .5 .. .TH qiv 1 "qiv" "fast image viewer for X" "X Tools" .SH NAME qiv \- a fast gdk3/gdk2 image viewer for X. .br .br Version: 3.0.1, released on 2025-04-03 .br by Andy Spiegl - http://qiv.spiegl.de/ - qiv.andy@spiegl.de .br originally by Adam Kopacz / KLOGRAFX.DE Network .br http://www.klografx.net/qiv/ - adam.k@klografx.de .SH SYNOPSIS .B qiv [options] file ... .SH DESCRIPTION .I qiv is an image viewer developed with gdk3/gdk2. As a result, .I qiv is faster than traditional image viewers such as \fIxv\fR or \fIxli\fR. .SH OPTIONS .TP .B \-h, \-\-help Print out a brief help message. .TP .B \-\-display \fIdisp\fB Open qiv window on display \fIdisp\fR. .TP .B \-F, \-\-file \fIfile | stdin\fB Read file names from \fIfile\fR or \fIstdin\fR, one name per line. This option can be specified multiple times to read from several files, and will not affect other file names passed on the command line. .TP .B \-u, \-\-recursivedir Change the behavior of qiv to recursively descend into the directories given on the command line. .TP .B \-L, \-\-followlinks With \-\-recursivedir, this allows a symlink to point to a directory. This is useful for organizing photo dirs into categories, but it is up to you to ensure that there are no symlink loops that would cause an infinite scan. .TP .B \-e, \-\-center Disable window centering. .TP .B \-w, \-\-fixed_width \fIx\fB Window with fixed width \fIx\fR. .TP .B \-W, \-\-fixed_zoom \fIx\fB. Window with fixed zoom factor (percentage \fIx\fR). .TP .B \-\-highDPIfactor FLOAT Resize everything by this factor to compensate for high (or also low) DPI screens. .TP .B \-x, \-\-root \fIfile\fB Set \fIfile\fR as the current desktop background (centered) and exit. .TP .B \-y, \-\-root_t \fIfile\fB Set \fIfile\fR as the current desktop background (tiled) and exit. .TP .B \-z, \-\-root_s \fIfile\fB Set \fIfile\fR as the current desktop background (stretched) and exit. .TP .B \-m, \-\-maxpect Expand image(s) to fit screen size while preserving aspect ratio. .TP .B \-t, \-\-scale_down Shrink image(s) which are larger than screen size to fit. .TP .B \-b, \-\-brightness \fIx\fB Set brightness to \fIx\fR (-32..32). .TP .B \-c, \-\-contrast \fIx\fB Set contrast to \fIx\fR (-32..32). .TP .B \-g, \-\-gamma \fIx\fB Set gamma to \fIx\fR (-32..32). .TP .B \-n, \-\-no_filter Disable filtering of images by extension. Normally, qiv will only load images with an image extension such as .jpg, .png, .gif ... This option lets you load any file as an image. .TP .B \-i, \-\-no_statusbar Disable statusbar. .TP .B \-I, \-\-statusbar Enable statusbar. .TP .B \-J, \-\-showJPEGcomments Enable display of JPEG comments. .TP .B \-E, \-\-showArtistName Enable display of artist (author) name (in JPEG images). .TP .B \-\-artist_ignore STRING Do NOT show artist name if it is equal to this string .TP .B \-p, \-\-transparency Enable transparency for transparent images. .TP .B \-a, \-\-do_grab Grab the pointer in windowed mode. .TP .B \-G, \-\-disable_grab Disable grabbing the pointer/kbd in fullscreen mode. Useful e.g. if qiv displays images on a display other than where it was invoked from. Use with caution! .TP .B \-v, \-\-version Print version information. .TP .B \-o, \-\-bg_color \fIx\fB Set root background color to named color \fIx\fR or 24 bit hex RGB triple in the format \fI#RRGGBB\fR. .TP .B \-C, \-\-cycle Change cycle behaviour. qiv will exit after last picture has been shown. .TP .B \-s, \-\-slide Start slideshow immediately. This can also be used for the desktop background (x/y/z). .TP .B \-r, \-\-random Randomize slideshow. .TP .B \-R, \-\-readonly Disable the deletion feature. .TP .B \-S, \-\-shuffle Shuffle images (random order with next/previous functionality). .TP .B \-d, \-\-delay \fIx\fB Set slideshow delay to \fIx\fR seconds. .TP .B \-f, \-\-fullscreen Use fullscreen window on start-up. .TP .B \-P, \-\-ignore_path_sort Sort all the image files by just their filename, ignoring the path. .TP .B \-M, \-\-merged_case_sort Sort all the image files in merged-case order (AaBbCc...). .TP .B \-K, \-\-mtime_sort Sort files by their modification time .TP .B \-N, \-\-numeric_sort A "smart" numeric sort that attempts to sort filenames with numbers in a logical manner. For instance: 2.jpg sorts before 10.jpg; 1foo.jpg through 10foo.jpg sorts after 1bar.jpg through 15bar.jpg (because "foo" comes after "bar"); and baz0001.jpg through baz0010.jpg sorts after baz01.jpg through baz99.jpg (because the longer group of zero-padded digits indicates that they shouldn't be intermingled). .TP .B \-D, \-\-no_sort Do not apply any sorting to the list of files. .TP .B \-T, \-\-watch Reload the image if it has changed on disk. .TP .B \-A, \-\-select_dir \fIdir\fB Store the selected files in \fIdir\fR (default is .qiv-select). .TP .B \-q, \-\-rotate \fIx\fB Rotate each image 90(x=1),180(x=2),270(x=3) degrees clockwise. If x=11 or x=13, the 90 or 270 degree rotation is conditional on the image fitting better if rotated. e.g. if the display is wide and a tall image is too tall to fit on the screen, it will be rotated. .TP .B \-l, \-\-autorotate Do NOT autorotate JPEGs according to EXIF rotation tag. Default is ON. .TP .B \-X, \-\-xineramascreen \fIx\fB Use monitor \fIx\fR as preferred screen .TP .B \-Y, \-\-source_profile \fIx\fB Use color profile file x as source profile for all images .TP .B \-Z, \-\-display_profile \fIx\fB Use color profile file x as display profile for all images .TP .B \-B, \-\-browse This option is useful when configuring qiv to be used with a file manager. qiv will scan the directory of the clicked image and allow you to scroll through those images. .TP .B \-\-trashbin Use users trash bin instead of .qiv-trash. Undeleting an image will not work, open the trash bin and restore the image instead. .TP .B \-\-vikeys Enable movement with h/j/k/l, vi-style (HJKL will do what hjkl previously did) .SH EXAMPLES qiv \-atsd2 *.jpg .br qiv \-\-maxpect \-\-root image.png .br qiv \-\-maxpect \-\-slide \-\-random \-\-delay=2 * .br qiv \-\-maxpect \-\-scale_down \-\-slide \-\-delay=2 `find / *` .br qiv \-\-bg_color 0000FF \-\-root image.png .br qiv \-\-bg_color blue \-\-root image.png .SH KEYS .EX space/left mouse/wheel right next picture backspace/right mouse/wheel left previous picture PgDn/wheel down 5 pictures forward PgUp/wheel up 5 pictures backward q/ESC/middle mouse exit 0-9 run 'qiv-command ' ^\fI...\fR run 'qiv-command ^\fI...\fR ' where \fI...\fR can be any string ?/F1 show keys F11/F12 in/decrease slideshow delay (1 second) a copy picture to .qiv-select A artist (author) info on/off d/D/del move picture to .qiv-trash (-R disables this feature) (if started with --trashbin picture is moved to users trash bin) u undelete the previously trashed image (not working if --trashbin is used) +/=/mouse btn 9 zoom in (+10% / +50% if above 100%) -/mouse btn 8 zoom out (10%) e center mode on/off f fullscreen mode on/off m scale to screen size on/off t scale down on/off X cycle through monitors s slide show on/off p transparency on/off r random order on/off b - brightness B + brightness c - contrast C + contrast g - gamma G + gamma o reset brightness, contrast, gamma h flip horizontally v flip vertically k rotate right l rotate left jt\fIx\fR jump to image number \fIx\fR jf\fIx\fR jump forward \fIx\fR images jb\fIx\fR jump backward \fIx\fR images enter/return reset zoom, rotation and color settings E display Exif information i statusbar on/off J JPEG comments on/off I iconify window w watch file on/off x center image on background y tile image on background z stretch image on background , grab on/off < turn on/off magnifying window arrow keys/wheel move image (in fullscreen mode) arrow keys/wheel+Shift move image faster (in fullscreen mode) NumPad-arrow keys+NumLock move image faster (in fullscreen mode) .EE .SH MOUSE CONTROLS .EX Button 1 next picture Button 1 (hold down) & Mouse-Move moving picture Button 2 quit Button 3 previous picture Wheel Up/Dn move image vertically Wheel Left/Right move image horizontally Extra mouse buttons (8,9) zoom out/in (10%) .EE .SH DELETING qiv doesn't actually delete files. It creates a directory named ".qiv-trash" and moves the images to that directory. qiv maintains the directory structure of your "deleted" images. You can also undelete the most recently trashed images in reverse order, which moves each file back into its original directory. There is a limit to how many deletions can be undone, but it should be pretty large (currently 1024 items). Sometimes this feature might be unwanted. To prevent accidents you can specify the "-R" option to disable this feature. If the "--trashbin" option is used qiv will move the deleted pictures to the users trash bin. In that case undeleting with pressing "u" will not work. Open the trash bin and restore the image instead. .SH IMWHEEL SUPPORT With XFree86 3.3.2+ server, using the wheel is seen as button 4 and 5 pressed. You only have to use "IMPS/2" or "Intellimouse" for protocol and add "ZAxisMapping 4 5 " in the "Pointer" section of XF86Config. If imwheel (a program used to emulate key pressed when wheel is used for program not supporting wheel), the following two lines must be add to imwheel config file : .P "qiv" .br @Exclude .SH USER-DEFINED KEYBOARD ACTIONS Keys 0-9 will invoke .B qiv-command with the key pressed as the first argument and the current image filename as the second argument. .B qiv-command is not distributed with qiv; it is to be supplied by the user. Thus, this feature could be enabled by placing a simple shell script such as the following in the command search path (for example, in the user's ~/bin directory): .P .EX #!/bin/sh # Argument sanity checking eliminated for brevity case $1 in 0|1|2|3|4|5|6|7|8|9) mkdir -f dir$1; mv "$fname" dir$1 ;; *) echo "unrecognized command"; exit ;; esac .EE .P If the first line of the output is like "NEWNAME=xxxxxxx" then qiv thinks that the filename of the currently displayed image has changed to this new name and updates its internal filelist. This is very useful when using qiv-command to rename files. .P Please also see the example that came together with qiv. .EE .SH AUTHORS .EX Adam Kopacz Andy Spiegl Darren Smith Pavel Andreev Decklin Foster Holger Mueller Scott Sams Serge Winitzki Frederic Crozat Rutger Nijlunsing John Knottenbelt Danny Tomas Ogren Erik Jacobsen Alfred Weyers Daniel Henning Kulander Ask Bjoern Hansen Adrian Lopez Y Furuhashi Wayne Davison Johannes Stezenbach OEyvind Kolaas Matthieu Castet Geoffrey T. Dairik Leopoldo Cerbaro Heikki Lehvaslaiho Larry Doolittle S. Dobrev Thomas Wiegner Barry deFreese Peter deWachter Akos Pasztory .EE .SH MISC .P qiv homepage: http://qiv.spiegl.de/ .P homepage of original author Adam Kopacz http://www.klografx.net/qiv/ .P Mail bug, reports and comments to Andy Spiegl .P Sending a SIGUSR1 to qiv will cause the program to flip to next picture. SIGUSR2 will move to previous. .P This program is covered by the GNU GPL; see the file COPYING for details. qiv-3.0.1/qiv.desktop0000664000175000001440000000117314774332451013374 0ustar andyusers[Desktop Entry] Version=1.0 Name=qiv Comment=Quick Image Viewer TryExec=qiv Exec=qiv -tB %U Icon=qiv StartupNotify=false Terminal=false Type=Application NoDisplay=true Categories=GNOME;GTK;Graphics;2DGraphics;RasterGraphics;Viewer; MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/webp;image/x-bmp;image/x-gray;image/x-icb;image/x-ico;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-xbitmap;image/x-xpixmap;image/x-pcx;image/svg+xml;image/svg+xml-compressed;image/vnd.wap.wbmp;image/heic; Keywords=Picture;Slideshow;Graphics; qiv-3.0.1/qiv.xpm0000664000175000001440000000652214774332451012532 0ustar andyusers/* XPM */ static const char *qiv_icon[] = { /* columns rows colors chars-per-pixel */ "16 16 170 2 ", " c #BD7B26", ". c #D99019", "X c #F59007", "o c #F59307", "O c #F4900B", "+ c #F99609", "@ c #FB9A09", "# c #FC9A09", "$ c #FC9A0B", "% c #FD9C0A", "& c #FD9C0C", "* c #FD9F0F", "= c #E48911", "- c #EF9611", "; c #F89B10", ": c #F9A011", "> c #FEA411", ", c #FDA413", "< c #FDA417", "1 c #FCA916", "2 c #FDA917", "3 c #F9A41D", "4 c #FCAA19", "5 c #FCAC1A", "6 c #FCAD1A", "7 c #FDAE1D", "8 c #DF9937", "9 c #DE9A37", "0 c #DE993E", "q c #DF9D3F", "w c #E19A26", "e c #FEAD21", "r c #FBAF24", "t c #FDB320", "y c #FEB825", "u c #FCBD24", "i c #FAB628", "p c #FBBB29", "a c #FDB828", "s c #FCBA28", "d c #FABA2E", "f c #FCBD2D", "g c #E3A133", "h c #EEAD31", "j c #E4AA3F", "k c #EFB032", "l c #F1B534", "z c #F2B435", "x c #F2B536", "c c #F7BD32", "v c #F0B339", "b c #FCC125", "n c #F8C62A", "m c #FDC52A", "M c #FEC12E", "N c #FCC92C", "B c #FCC331", "V c #F8C433", "C c #F9C732", "Z c #FBC036", "A c #FDC234", "S c #F8C536", "D c #F7CC31", "F c #F8CB30", "G c #F9C932", "H c #F9C835", "J c #FAC936", "K c #FCC934", "L c #FDC835", "P c #FEC834", "I c #FECB36", "U c #FDCE36", "Y c #F6CE3B", "T c #FDC838", "R c #FDCA3A", "E c #FCD13D", "W c #FDD43F", "Q c #B38447", "! c #B8975D", "~ c #BE9C5B", "^ c #B69862", "/ c #B29970", "( c #DC9D42", ") c #D69B4C", "_ c #D89C4C", "` c #C49951", "' c #CC9E5B", "] c #D49D50", "[ c #D6A458", "{ c #E5A544", "} c #F1B842", "| c #E8B655", " . c #C3A266", ".. c #DBB168", "X. c #E1BE75", "o. c #E3BC7F", "O. c #F4CB42", "+. c #F5CF42", "@. c #FDCE40", "#. c #FDCF42", "$. c #F3CC4E", "%. c #FDD742", "&. c #FAD446", "*. c #FDD445", "=. c #FCD645", "-. c #FCDC47", ";. c #FED648", ":. c #FCDA4A", ">. c #FCDE48", ",. c #FDDE49", "<. c #FDDF49", "1. c #ECC25C", "2. c #FDE04C", "3. c #FDE353", "4. c #FCE254", "5. c #F8E55E", "6. c #F8E858", "7. c #FDEA5C", "8. c #DFCC76", "9. c #E8CB6B", "0. c #E8CB6E", "q. c #E8CE6F", "w. c #E6D46D", "e. c #E9C872", "r. c #E8C973", "t. c #EACE72", "y. c #E8C578", "u. c #E7CB7D", "i. c #E9D675", "p. c #E7D478", "a. c #EED778", "s. c #E2D978", "d. c #ECE16B", "f. c #F2E862", "g. c #F5EB66", "h. c #FCEE61", "j. c #F4E96A", "k. c #FCF060", "l. c #FDF262", "z. c #FAF36D", "x. c #CCAF86", "c. c #DDB993", "v. c #DCC78E", "b. c #D4CE8F", "n. c #DECC97", "m. c #DBD594", "M. c #E5CA8C", "N. c #E5DA8E", "B. c #E9D88D", "V. c #E2CE95", "C. c #E1C29D", "Z. c #E3DE9E", "A. c #ECEA84", "S. c #F2F282", "D. c #F1F384", "F. c #F0F28A", "G. c #CBC2A0", "H. c #CCC7AF", "J. c #DFCBA5", "K. c #D4C8AA", "L. c #D2D2AF", "P. c #E8DFAF", "I. c #E3D4B1", "U. c #E0E3A1", "Y. c #E5E1B0", "T. c #D0CCCE", "R. c #D3D5C6", "E. c #DBDFC2", "W. c #D4D1D1", "Q. c None", /* pixels */ "Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", "Q.Q.Q.Q.P.N.p.q.0.u.V.I.Q.Q.Q.Q.", "Q.Q.Y.a.+.D G J H V c } X.Q.Q.Q.", "Q.Q.i.F N U %.>.,.=.R f v ..Q.Q.", "Q.B.O.m E <.6.f.g.h.4.@.d j Q.Q.", "Q.t.n K -.5.s.b.m.A.z.3.T h .Q.", "Q.r.b I 2.w.G.T.W.L.D.k.*.l ~ Q.", "Q.e.u P ,.8.H.Q.Q.R.F.l.;.x ! Q.", "Q.y.i M W 9.K.Q.Q.E.S.7.#.k ^ Q.", "Q.M.z y L $.v.Q.Q.U.j.:.Z g / Q.", "Q.J.| 7 s B 1.n.Z.d.&.A r w ` Q.", "Q.Q.o.3 6 t p S Y C a e < ; . Q.", "Q.Q.C.{ : > 1 4 5 2 , * $ O Q.", "Q.Q.Q.c.q - @ & % # + o X = Q Q.", "Q.Q.Q.Q.x.[ 0 8 9 ( _ ) ] ' Q.Q.", "Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q." }; qiv-3.0.1/README.COPYING0000664000175000001440000004310714774332451013174 0ustar andyusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. qiv-3.0.1/lib/0000775000175000001440000000000014774332451011746 5ustar andyusersqiv-3.0.1/lib/getopt1.c0000664000175000001440000001105314774332451013475 0ustar andyusers/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. This file is part of the GNU C Library. Its master source is NOT part of the C library, however. The master source lives in /gd/gnu/lib. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include "getopt.h" #if !defined (__STDC__) || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* Not ELIDE_CODE. */ #ifdef TEST #include int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ qiv-3.0.1/lib/getopt.c0000664000175000001440000007007414774332451013424 0ustar andyusers/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc. This file is part of the GNU C Library. Its master source is NOT part of the C library, however. The master source lives in /gd/gnu/lib. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO #define _NO_PROTO #endif #include #ifdef HAVE_CONFIG_H #include #endif #if !defined (__STDC__) || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ #include #include #endif /* GNU C library. */ #ifdef VMS #include #if HAVE_STRING_H - 0 #include #endif #endif #if defined (WIN32) && !defined (__CYGWIN32__) /* It's not Unix, really. See? Capital letters. */ #include #define getpid() GetCurrentProcessId() #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ #ifdef HAVE_LIBINTL_H # include # define _(msgid) gettext (msgid) #else # define _(msgid) (msgid) #endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include #define my_index strchr #else /* Avoid depending on library functions or files whose names are inconsistent. */ char *getenv (); static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ #if !defined (__STDC__) || !__STDC__ /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); #endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ static const char *nonoption_flags; static int nonoption_flags_len; static int original_argc; static char *const *original_argv; /* Make sure the environment variable bash 2.0 puts in the environment is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ static void store_args (int argc, char *const *argv) __attribute__ ((unused)); static void store_args (int argc, char *const *argv) { /* XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ original_argc = argc; original_argv = argv; } text_set_element (__libc_subinit, store_args); #endif /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined (__STDC__) && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined (__STDC__) && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind = 1; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #ifdef _LIBC if (posixly_correct == NULL && argc == original_argc && argv == original_argv) { /* Bash 2.0 puts a special variable in the environment for each command it runs, specifying which ARGV elements are the results of file name wildcard expansion and therefore should not be considered as options. */ char var[100]; sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ()); nonoption_flags = getenv (var); if (nonoption_flags == NULL) nonoption_flags_len = 0; else nonoption_flags_len = strlen (nonoption_flags); } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { optarg = NULL; if (!__getopt_initialized || optind == 0) { optstring = _getopt_initialize (argc, argv, optstring); optind = 1; /* Don't scan ARGV[0], the program name. */ __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #ifdef _LIBC #define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && nonoption_flags[optind] == '1')) #else #define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ qiv-3.0.1/lib/getopt.h0000664000175000001440000001112314774332451013417 0ustar andyusers/* Declarations for getopt. Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. This file is part of the GNU C Library. Its master source is NOT part of the C library, however. The master source lives in /gd/gnu/lib. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if defined (__STDC__) && __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #if defined (__STDC__) && __STDC__ #ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int argc, char *const *argv, const char *shortopts); #else /* not __GNU_LIBRARY__ */ extern int getopt (); #endif /* __GNU_LIBRARY__ */ extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ extern int getopt (); extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* __STDC__ */ #ifdef __cplusplus } #endif #endif /* _GETOPT_H */ qiv-3.0.1/debian/0000775000175000001440000000000014774332451012422 5ustar andyusersqiv-3.0.1/debian/rules0000775000175000001440000000117114774332451013502 0ustar andyusers#!/usr/bin/make -f DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) DEB_PATCHDIRS := debian/patches debian/patches_$(DEB_HOST_ARCH) include /usr/share/cdbs/1/class/makefile.mk include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/rules/simple-patchsys.mk DEB_MAKE_EXTRA_ARGS += 'CC=$(CC)' update-config:: [ -f qiv-command ] || mv contrib/qiv-command.example qiv-command [ -f gps2url.py ] || mv contrib/gps2url.py gps2url.py reverse-config:: [ ! -f qiv-command ] || mv qiv-command contrib/qiv-command.example [ ! -f gps2url.py ] || mv gps2url.py contrib/gps2url.py clean:: rm -f qiv xmalloc.o qiv-3.0.1/debian/docs0000664000175000001440000000003514774332451013273 0ustar andyusersintro.jpg README.TODO README qiv-3.0.1/debian/install0000664000175000001440000000011114774332451014004 0ustar andyusersqiv usr/bin qiv.desktop usr/share/applications qiv.png usr/share/pixmaps qiv-3.0.1/debian/watch0000664000175000001440000000007114774332451013451 0ustar andyusersversion=3 http://qiv.spiegl.de/download/qiv-(.*)-src.tgz qiv-3.0.1/debian/control0000664000175000001440000000170414774332451014027 0ustar andyusersSource: qiv Section: graphics Priority: extra Maintainer: Bart Martens Build-Depends: cdbs, debhelper (>= 5), libgtk-3-dev, libx11-dev, libmagic-dev, libexif-dev, liblcms2-dev Standards-Version: 3.7.3 Homepage: http://qiv.spiegl.de/ Package: qiv Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Recommends: libwmf-0.2-7-gtk, librsvg2-common Description: A quick image viewer for X Quick Image Viewer (qiv) is a very small and pretty fast GDK3.0 image viewer. Features include zoom, maxpect, scale down, fullscreen, brightness/contrast/gamma correction, slideshow, pan with keyboard and mouse, rotate left/right, flip, delete (move to .qiv-trash/), jump to image x, jump forward/backward x images, filename filter, and you can use qiv to set your X11-Desktop background. With multi monitor support. . qiv also supports the assignment of external commands (like metacam) to unused keys. . Homepage: http://qiv.spiegl.de/ qiv-3.0.1/debian/examples0000664000175000001440000000002714774332451014162 0ustar andyusersqiv-command gps2url.py qiv-3.0.1/debian/qiv.mime0000664000175000001440000000361014774332451014072 0ustar andyusersimage/gif; qiv -tfi %s; description="GIF Image"; test=test "$DISPLAY"; nametemplate=%s.gif; priority=4 image/jpeg; qiv -tfi %s; description="JPEG Image"; test=test "$DISPLAY"; nametemplate=%s.jpeg; priority=4 image/pjpeg; qiv -tfi %s; description="JPEG Image"; test=test "$DISPLAY"; nametemplate=%s.jpeg; priority=4 image/tiff; qiv -tfi %s; description="TIFF Image"; test=test "$DISPLAY"; nametemplate=%s.tiff; priority=4 image/x-portable-bitmap; qiv -tfi %s; description="PBM Image"; test=test "$DISPLAY"; nametemplate=%s.pbm; priority=4 image/x-portable-graymap; qiv -tfi %s; description="PGM Image"; test=test "$DISPLAY";nametemplate=%s.pgm; priority=4 image/x-portable-pixmap; qiv -tfi %s; description="PPM Image"; test=test "$DISPLAY"; nametemplate=%s.ppm; priority=4 image/x-xpixmap; qiv -tfi %s; description="XPM Image"; test=test "$DISPLAY"; nametemplate=%s.xpm; priority=4 image/bmp; qiv -tfi %s; description="BMP Image"; test=test "$DISPLAY"; nametemplate=%s.bmp; priority=4 image/x-bmp; qiv -tfi %s; description="BMP Image"; test=test "$DISPLAY"; nametemplate=%s.bmp; priority=4 image/x-ms-bmp; qiv -tfi %s; description="BMP Image"; test=test "$DISPLAY"; nametemplate=%s.bmp; priority=4 image/x-rgb; qiv -tfi %s; description="RGB Image"; test=test "$DISPLAY"; nametemplate=%s.rgb; priority=4 image/png; qiv -tfi %s; description="PNG Image"; test=test "$DISPLAY"; nametemplate=%s.png; priority=4 image/pcx; qiv -tfi %s; description="PCX Image"; test=test "$DISPLAY"; nametemplate=%s.pcx; priority=4 image/pm; qiv -tfi %s; description="PM Image"; test=test "$DISPLAY"; nametemplate=%s.pm; priority=4 image/svg+xml; qiv -tfi %s; description="SVG Image"; test=test "$DISPLAY"; nametemplate=%s.svg; priority=4 image/webp; qiv -tfi %s; description="WEBP Image"; test=test "$DISPLAY"; nametemplate=%s.webp; priority=4 image/heic; qiv -tfi %s; description="HEIC Image"; test=test "$DISPLAY"; nametemplate=%s.heic; priority=4 qiv-3.0.1/debian/compat0000664000175000001440000000000214774332451013620 0ustar andyusers7 qiv-3.0.1/debian/manpages0000664000175000001440000000000614774332451014134 0ustar andyusersqiv.1 qiv-3.0.1/debian/copyright0000664000175000001440000000664414774332451014367 0ustar andyusersThis package was debianized by Mitch Blevins on Sun, 8 Nov 1998 23:37:24 -0500 It was downloaded from http://qiv.spiegl.de/download/ The homepage of the original author Adam Kopacz is http://www.klografx.net/qiv/ Upstream Authors: (see below) Adam Kopacz Andy Spiegl Darren Smith Pavel Andreev Decklin Foster Holger Mueller Scott Sams Serge Winitzki Frederic Crozat Rutger Nijlunsing John Knottenbelt Danny Tomas Ogren Erik Jacobsen Alfred Weyers Daniel Henning Kulander Ask Bjoern Hansen Adrian Lopez Y Furuhashi Wayne Davison Johannes Stezenbach OEyvind Kolaas Matthieu Castet Geoffrey T. Dairik Leopoldo Cerbaro Heikki Lehvaslaiho Larry Doolittle S. Dobrev Thomas Wiegner Barry deFreese Peter deWachter Akos Pasztory Copyright: Copyright (C) 1989-2009 the above-mentioned authors See "Changelog" for details who did what when. Copyright (C) 1987-1997 Free Software Foundation, Inc. For lib/getopt*. License: This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 dated June, 1991. This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. On Debian GNU/Linux systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL'. The file debian/patches/06.xmalloc.diff is: * Created by Kevin Locke (from numerous canonical examples) * * I hereby place this file in the public domain. It may be freely reproduced, * distributed, used, modified, built upon, or otherwise employed by anyone * for any purpose without restriction. Kevin Locke wrote on bug 383113: I have attached my stock do-or-die memory handling functions (public domain, but easily relicensable to GPL if desired), and a patch to incorporate those functions into qiv. qiv-3.0.1/debian/changelog0000664000175000001440000003030314774332451014273 0ustar andyusersqiv (3.0.1) stable; urgency=medium * new upstream version; see Changelog for details -- Andy Spiegl Thu, 03 Apr 2025 08:35:00 +0200 qiv (3.0.0) stable; urgency=medium * new upstream version; see Changelog for details -- Andy Spiegl Mon, 31 Mar 2025 20:35:00 +0200 qiv (2.9.0) stable; urgency=medium * intermediate upstream version; see Changelog for details -- Andy Spiegl Mon, 17 Mar 2025 19:15:00 +0100 qiv (2.3.4) stable; urgency=medium * new upstream version; see Changelog for details -- Andy Spiegl Mon, 3 Mar 2025 18:15:00 +0100 qiv (2.3.3) stable; urgency=medium * new upstream version; see Changelog for details -- Andy Spiegl Sat, 28 Jan 2023 21:50:58 +0100 qiv (2.3.2) stable; urgency=low * new upstream version; see Changelog for details -- Andy Spiegl Fri, 03 Nov 2017 19:00:38 +0100 qiv (2.3.1) stable; urgency=low * new upstream version; see Changelog for details -- Andy Spiegl Fri, 20 Dec 2013 01:49:11 +0100 qiv (2.2.4) unstable; urgency=low * new upstream version; see Changelog for details -- Andy Spiegl Mon, 02 May 2011 16:26:51 +0200 qiv (2.2.4pre) unstable; urgency=low * new upstream version; see Changelog for details -- Andy Spiegl Wed, 14 Apr 2010 18:00:00 +0200 qiv (2.2.3) unstable; urgency=low * new upstream version; see Changelog for details -- Andy Spiegl Wed, 10 Jan 2010 22:34:00 +0100 qiv (2.2.3pre) unstable; urgency=low * new upstream version; see Changelog for details -- Andy Spiegl Wed, 02 Aug 2009 23:59:00 +0200 qiv (2.2.2) unstable; urgency=low * new upstream version; see Changelog for details -- Andy Spiegl Wed, 30 May 2009 23:59:00 +0200 qiv (2.2.1) unstable; urgency=low * new upstream version; see Changelog for details -- Andy Spiegl Wed, 26 May 2009 18:30:00 +0200 qiv (2.2) unstable; urgency=low * migration from imlib1 to imlib2 * new upstream version; see Changelog for details -- Andy Spiegl Thu, 30 Apr 2009 12:00:00 +0200 qiv (2.1) unstable; urgency=low * Adam Kopacz delegated to Andy Spiegl as new upstream maintainer * new homepage: http://qiv.spiegl.de/ * new upstream version; see Changelog for details -- Andy Spiegl Thu, 05 Mar 2009 23:19:00 +0100 qiv (2.1-pre13) unstable; urgency=low * small patch to prevent segfault on amd64 * removed debian/lintian/qiv -- Andy Spiegl Thu, 24 May 2007 11:19:43 +0200 qiv (2.1-pre12) unstable; urgency=low * new upstream developer version; see Changelog for details -- Andy Spiegl Wed, 02 May 2007 23:00:00 +0200 qiv (2.1-pre11) unstable; urgency=low * new upstream developer version; see Changelog for details -- Andy Spiegl Wed, 25 Apr 2007 04:00:00 +0200 qiv (2.0-8) unstable; urgency=low * debian/README.Debian, debian/docs: Removed README.Debian, and install debian/NEWS.Debian. Closes: #403936. * debian/qiv.mime: Updated. Closes: #404220. Thanks to Roman Galeyev . -- Bart Martens Sat, 27 Jan 2007 17:02:56 +0100 qiv (2.0-7) unstable; urgency=low * debian/NEWS.Debian: Added. * debian/patches/10_qiv-nosort_2.diff: Added. Closes: #383110. * debian/patches/11_no_background_opts_2.diff: Added. Closes: #351816. -- Bart Martens Wed, 6 Dec 2006 19:58:52 +0100 qiv (2.0-6) unstable; urgency=low * debian/patches/07_no_background_opts.diff: Added. Closes: #351816. * debian/patches/08_hide_therealqiv.diff: Added, to hide "therealqiv". * debian/patches/09_man_xscreensaver.diff: Added. Closes: #360514. * debian/bin/qiv: Use "exec". Closes: #399596. -- Bart Martens Wed, 22 Nov 2006 14:52:29 +0100 qiv (2.0-5) unstable; urgency=low * New maintainer. Closes: #398124. * Acknowledge NMU's. Closes: #320115, #347042. * debian/*: Repackaged with cdbs. * debian/control: Updated build-depends to gdk-imlib11-dev. * debian/patches/*: Converted dpatches to diff files. * debian/patches/02.typo_envoked.diff: Added. Closes: #311232. Patch by A Costa , thanks. * debian/patches/04.qiv-nosort.diff: Added. Closes: #383110. Patch by Kevin Locke , thanks. * debian/patches/05.qiv-manpage-options.diff: Added. Closes: #383108. Patch by Kevin Locke , thanks. * debian/patches/06.xmalloc.diff: Added. Closes: #383113. Patch by Kevin Locke , thanks. * debian/watch: Added. * debian/bin/qiv, debian/lintian/qiv, debian/rules: Add wrapper using XLIB_SKIP_ARGB_VISUALS=1 as workaround for problem in qiv with X composite extension. Closes: #326849. Thanks to Joerg Platte . -- Bart Martens Sun, 12 Nov 2006 09:21:38 +0100 qiv (2.0-4.2) unstable; urgency=low * NMU. * debian/patches/02.improves_bgimage_setting.dpatch, debian/patches/00list: Removed patch with regression. Closes: #320115. * debian/copyright: Fixed old-fsf-address-in-copyright-file. * debian/control: Standards version. * debian/control: Adjusted homepage. -- Bart Martens Sat, 13 May 2006 21:00:04 +0200 qiv (2.0-4.1) unstable; urgency=low * Non-maintainer upload. * Update build-deps for xlibs-dev removal; closes: #347042. -- Justin Pryzby Sat, 14 Jan 2006 15:23:43 -0500 qiv (2.0-4) unstable; urgency=low * New maintainer (Closes: #304096) * added Homepage to long description * use dpatch now * Closes: #294293: qiv should support the new background setting mechanism; used provided patch * Closes: #262986: more customizable keys for qiv-command; used provided patch -- Christoph Wegscheider Sun, 22 May 2005 09:03:12 +0200 qiv (2.0-3) unstable; urgency=low * eliminated warning about missing Xinerama extension on non-Xinerama displays * correctly center image on Xinerama displays * Thanks to Geoffrey T. Dairiki for these patches! -- Martin Pitt Wed, 16 Jun 2004 21:04:31 +0200 qiv (2.0-2) unstable; urgency=low * enabled Xinerama support in Makefile (closes: #253880) -- Martin Pitt Sun, 13 Jun 2004 11:34:10 +0200 qiv (2.0-1) unstable; urgency=low * new upstream version; key "PageUp" now does not crash any more when there are less than five pictures. closes: #246732 * updated description -- Martin Pitt Sun, 23 May 2004 23:53:16 +0200 qiv (1.9-4) unstable; urgency=low * short option for --ignore_path_sort is now correctly documented as -P (manpage and --help). (closes: #234174) -- Martin Pitt Mon, 23 Feb 2004 19:46:04 +0100 qiv (1.9-3) unstable; urgency=low * Added option -B / --noblank to disable screensaver and DPMS during execution (closes: #178668) -- Martin Pitt Wed, 4 Feb 2004 23:42:46 +0100 qiv (1.9-2) unstable; urgency=low * shortened NAME section in manpage (closes: #230752) * stated copyright holders in debian/copyright -- Martin Pitt Tue, 3 Feb 2004 20:07:11 +0100 qiv (1.9-1) unstable; urgency=low * new upstream release (some new features, upstream took over my patches) * correctly install README.CHANGES as upstream changelog * updated long description -- Martin Pitt Sun, 14 Dec 2003 23:38:53 +0100 qiv (1.8-6) unstable; urgency=low * qiv.mime: now gives option '-n' to ignore file extension (better for mail attachments etc.) (closes: #217226) * changed my Maintainer address -- Martin Pitt Tue, 28 Oct 2003 17:49:31 +0100 qiv (1.8-5) unstable; urgency=low * undeleting a file now also works on FAT file systems (closes: #210550) (this really was the last spot using link(), I checked!) -- Martin Pitt Fri, 12 Sep 2003 12:16:29 +0200 qiv (1.8-4) unstable; urgency=low * deleting a file now also works on FAT file systems (closes: #209079) * updated Standards-Version to 3.6.1 (no changes required) -- Martin Pitt Tue, 9 Sep 2003 11:26:37 +0200 qiv (1.8-3) unstable; urgency=low * new maintainer (closes: #193604) * debian/control: updated maintainer and wrong upstream URL * debian/copyright: replaced copyright with standard GPL clause * fixed build-deps: removed unnecessary libglib1.2-dev, added gdk-imlib-dev as alternative to make it Woody-compatible * debian/qiv.mime: added image/pjpeg type (closes: #193643) * image.c, reload_image(): now checked image loading for errors, thanks to Niels Andersen; patch sent to upstream who included it (closes: #194575) * updated to standards version 3.5.10: DH_COMPAT -> debian/compat, respect DEB_BUILD_OPTIONS * cleaned up debian/ directory: removed dirs, docs (debian/rules does that now) * removed debian/patches/: Makefile patch not needed any more, patch to options.c incorporated into package.diff.gz (also sent to upstream who included it in next version) * complete rewrite of debian/rules * included intro.jpg and qiv-command.example in package * removed Emacs' local variables stuff from Debian changelog -- Martin Pitt Mon, 26 May 2003 20:34:28 +0200 qiv (1.8-2) unstable; urgency=low * Builded against gdk-imlib1. -- Luis Bustamante Thu, 6 Feb 2003 07:25:08 -0500 qiv (1.8-1) unstable; urgency=low * The I-will-take-care-of-qiv release. * Package builded from the scratch. Updated to standards version 3.5.8. * New maintainer (closes: #176329). * New upstream release (closes: #156155). * It seems qiv handles bmp files correctly now (closes: #120681). * Builded against gdk-imlib2 (closes: #158926). * Better delay handling for slideshow. Thanks to Samuele Giovanni Tonon (closes: #159019). * Stop clearing when panning in full screen mode (closes: #150951). * Show images with unknown extensions using -n option (closes: #99811). -- Luis Bustamante Thu, 16 Jan 2003 12:00:55 -0500 qiv (1.7-0.2) unstable; urgency=medium * Non-maintainer upload. * Move man page from /usr/man to /usr/share/man (closes: #141105). -- Colin Watson Thu, 18 Apr 2002 00:08:22 +0100 qiv (1.7-0.1) unstable; urgency=low * NMU * New Upstream release (Closes: #110115) * Upstream fixed: (Closes: #97090) * moved binary and manpage to /usr, not /usr/X11R6 * This isnt a Debian native package, lets give it an orig.tar.gz, not a tar.gz.. Tsk. -- Michael Beattie Fri, 22 Feb 2002 23:57:20 +1200 qiv (1.6-1) unstable; urgency=low * Upstream release (closes: #82827) -- Mitch Blevins Sun, 11 Feb 2001 16:07:31 -0600 qiv (1.5-2) unstable; urgency=low * Added Build-Depends (closes: Bug#82405) -- Mitch Blevins Mon, 15 Jan 2001 23:53:58 -0600 qiv (1.5-1) unstable; urgency=low * Upstream release (closes: Bug#77504) * Fixed typo in description (closes: Bug#56126) * Added mime types to /etc/mailcap (closes: Bug#61598) -- Mitch Blevins Thu, 4 Jan 2001 19:08:35 -0600 qiv (1.1-1) unstable; urgency=low * Upstream release -- Mitch Blevins Mon, 31 May 1999 23:09:11 -0400 qiv (1.0-5) unstable; urgency=low * Recompiled for gtk/glib 1.2 -- Mitch Blevins Sat, 6 Mar 1999 01:28:09 -0500 qiv (1.0-4) unstable; urgency=low * Recomplied to fix multiple libglib dependencies -- Mitch Blevins Tue, 2 Feb 1999 10:30:10 -0500 qiv (1.0-3) unstable; urgency=low * Removed install from default target in Makefile -- Mitch Blevins Mon, 11 Jan 1999 07:48:26 -0500 qiv (1.0-2) unstable; urgency=low * Updated libjpeg dependancies -- Mitch Blevins Sat, 14 Nov 1998 02:27:23 -0500 qiv (1.0-1) unstable; urgency=low * Initial Release. -- Mitch Blevins Sun, 8 Nov 1998 23:37:24 -0500 qiv-3.0.1/contrib/0000775000175000001440000000000014774332451012640 5ustar andyusersqiv-3.0.1/contrib/qiv-command.example0000775000175000001440000001243614774332451016441 0ustar andyusers#!/bin/bash ### ### QUICK IMAGE VIEWER "qiv-command" file ### http://qiv.spiegl.de/ ### ### This file will be launched by QIV if you push 0-9 (or any other free key) ### NEW: Now you can use all free keys for qiv-command. ### NEW: If you press "X" followed by any string, ### qiv-command is called with X and this string ### ### Just put it in a directory that is in your path ### ### Note: ### If the first line of the output is like "NEWNAME=xxxxxxx" then qiv ### thinks that the filename of the currently displayed image has ### changed to this new name and updates its internal filelist. ### This is very useful when using qiv-command to rename files. # # some examples by Andy Spiegl # Created: 2002-05-12 # Last change: 2021-12-14 # # more examples (renaming, jpg comments) by Clint Pachl # # needs jhead to rotate JPEG without loss of Exif Jpeg headers # jhead is: # Program for extracting Digicam setting information from Exif Jpeg headers # used by most Digital Cameras. v2.6 by Matthias Wandel, Dec 26 2006 # http://www.sentex.net/~mwandel/jhead mwandel@sentex.net # Syntax: qiv-command [pressed_key] [image_filename_with_full_path] pressed_key=$1 # key(s) pressed in qiv filename=$2 # image filename with full path echo "You pressed the $pressed_key key while watching $filename" case "$pressed_key" in 0) # do something with the image ($2) -> # # example: copy # cp "$2" "/home/myfiles/download/"; # # example: move # mv "$2" "/home/myfiles/download/"; # echo "NEWNAME=/home/myfiles/download/$2"; # # example: show EXIF Header using "exiftool" or "jhead" # exiftool "$filename" # jhead "$filename" # more sophisticated for better infos (adjust paths!) # if [ -r $HOME/local/var/exiftool.tags.for.qiv-command ]; then # exiftool `xargs < $HOME/local/var/exiftool.tags.for.qiv-command` "$filename" \ # | grep -v -f $HOME/local/var/exiftool.grep-exclude-pattern.for.qiv-command # jhead -nofinfo "$filename" | grep -i -E '^(JPEG Quality |Caption )' # else # jhead -nofinfo "$filename" # fi echo -ne "0 was pushed.\nStart your own programs by editing the\n\"$0\" file!"; ;; 1|2|3|4) echo -ne "$pressed_key was pushed.\nStart your own programs by editing the\n\"$0\" file!"; ;; 5) # Open picture for editing with gimp. Send stdout/stderr to /dev/null, otherwise qiv will wait for gimp to end. gimp "$filename" > /dev/null 2>&1 & ;; 6) # Modify comment header. Fire up an xterm running EDITOR to edit comment. #xterm -e jhead -ce "$filename" jhead -ce "$filename" ;; 7) # Open picture for editing with gimp. Send stdout/stderr to /dev/null, otherwise qiv will wait for gimp to end. gimp "$filename" > /dev/null 2>&1 & ;; 8) # lossless rotation of JPG, without losing EXIF tags echo 2>&1 "Rotating to the left." jhead -cmd "jpegtran -perfect -rotate 270 -outfile &o &i" "$filename" >/dev/null # set timestamp of file to Date/Time when the photo was taken jhead -q -ft "$filename" >/dev/null ;; 9) # lossless rotation of JPG, without losing EXIF tags echo 2>&1 "Rotating to the right." jhead -cmd "jpegtran -perfect -rotate 90 -outfile &o &i" "$filename" >/dev/null # set timestamp of file to Date/Time when the photo was taken jhead -q -ft "$filename" >/dev/null ;; # with "^"-prefix: forced (i.e. possibly NOT lossless) rotation ^8) # rotate JPG, but possibly losing quality echo 2>&1 "Forcing rotation to the left." jhead -cmd "jpegtran -rotate 270 -outfile &o &i" "$filename" >/dev/null # set timestamp of file to Date/Time when the photo was taken jhead -q -ft "$filename" >/dev/null ;; ^9) # rotate JPG, but possibly losing quality echo 2>&1 "Forcing rotation to the right." jhead -cmd "jpegtran -rotate 90 -outfile &o &i" "$filename" >/dev/null # set timestamp of file to Date/Time when the photo was taken jhead -q -ft "$filename" >/dev/null ;; ^g) # call gps2url to extract GPS coordinates from an image and # call firefox with google maps url if the GPS info exists gps2url "$filename" & ;; ^*) # Rename image directly from qiv. The timestamp of the current image will be # automatically embedded in the new filename. This action is invoked by typing: # # ^ # # Echoing the `NEWNAME=new_img_name` line signals qiv to update it's file list # with the new filename. img_timestamp=$(date -r `stat -f '%m' "$filename"` +'%y%m%d%H%M%S') new_img_name=${pressed_key#^} new_img_name=`echo "$new_img_name" | tr ' ' '_'` new_img_name=${new_img_name%.[Jj][Pp][Gg]}-${img_timestamp}.jpg [[ -f "$new_img_name" ]] && exit 1 mv "$filename" "$new_img_name" echo "NEWNAME=$new_img_name" ;; V) qiv -h ;; *) cat <<-EOF Commands: 0 show EXIF header 6 edit JPEG comment 7 start GIMP to edit current image 8 lossless rotate left 9 lossless rotate right ^8 non-perfect rotate left (use if '8' fails) ^9 non-perfect rotate right (use if '9' fails) ^STRING rename current file to STRING Within qiv you simply press a key from 0-9 or any other unused key! "$pressed_key" not defined yet. Quitting. EOF exit 1 esac exit 0 qiv-3.0.1/contrib/qiv.spec0000664000175000001440000000743714774332451014326 0ustar andyusers# Should work on most rpm based distros. Package names might differ here and there. # Tested on RHEL6/CentOS6, make sure epel repository is enabled. Name: qiv Version: 2.3.2 Release: 1 Summary: A quick image viewer for X Source0: http://spiegl.de/qiv/download/%{name}-%{version}.tar.gz License: GPL Url: http://spiegl.de/qiv/ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot BuildRequires: gtk2-devel BuildRequires: libexif-devel BuildRequires: imlib2-devel BuildRequires: file-devel BuildRequires: pkgconfig BuildRequires: lcms2-devel BuildRequires: libtiff-devel # This has most likely to be another jpeg package on distros other than RHEL/CentOS BuildRequires: libjpeg-turbo-devel Requires: gtk2 Requires: libexif Requires: imlib2 Requires: file Requires: lcms2 Group: Graphics %description Quick Image Viewer (qiv) is a very small and pretty fast GDK2.0/Imlib2 image viewer. Features include zoom, maxpect, scale down, fullscreen, brightness/contrast/gamma correction, slideshow, pan with keyboard and mouse, rotate left/right, flip, delete (move to .qiv-trash/), jump to image x, jump forward/backward x images, filename filter, and you can use qiv to set your X11-Desktop background. With multi monitor support. qiv also supports the assignment of external commands (like metacam) to unused keys. %prep %setup -q -n %{name}-%{version} %build echo RPM_BUILD_ROOT ist $RPM_BUILD_ROOT echo pwd ist pwd make CFLAGS="$RPM_OPT_FLAGS" %install echo pwd ist pwd mkdir -p $RPM_BUILD_ROOT%{_bindir} mkdir -p $RPM_BUILD_ROOT/{%{_bindir},%{_mandir}/man1} DISPLAY="" make PREFIX=$RPM_BUILD_ROOT%{_prefix} install # Hmm. Any better ideas how to achieve this? mkdir -p %{_builddir}/%{name}-%{version}/examples/ cp -p %{_builddir}/%{name}-%{version}/contrib/gps2url.py %{_builddir}/%{name}-%{version}/examples cp -p %{_builddir}/%{name}-%{version}/contrib/qiv-command.example %{_builddir}/%{name}-%{version}/examples/qiv-command %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc README Changelog README.COPYING README.INSTALL intro.jpg examples %{_bindir}/qiv %{_mandir}/man1/qiv.1* %{_prefix}/share/applications/qiv.desktop %{_prefix}/share/pixmaps/qiv.png %changelog * Thu Oct 10 2017 Thomas Wiegner 2.3.2 - qiv changes since v2.3.1: + [tw] fix: window sometimes recentered, when moved around with mouse + [as] fix Makefile for cross-compiling: Make pkg-config substitutable (Debian Bug#879108) + [tw] add specfile to build rpm for CentOS + [tw] add option --trashbin to use trash bin instead of .qiv-trash when deleting images + [as] add ability (and options) to display JPEG comments + [as] more sophisticated exiftool call in qiv-command example + [tw] fix inconsistent fixed-zoom behaviour + [tw] Don't try to rotate if file is not an image + [tw] get rid of some more XID collisions + [tw] Fix occasionally erratic behaviour of qiv statusbar + [tw] Fix xpm autodetection with libmagic + [tw] Fix small artefacts in pictures which might happen when running remote over slow link (patch by Derek Schrock) + [tw] update image after it is exposed in window mode + [js/tw] fix broken "-no-filter" option libmagic filter now works on symlinks + [tw] fix linking order in "make debug", did not work in some newer gcc versions + [as] turn on EXIF autorotation by default + [tw] Add option to sort files by modification time. (patch by Stefan Rüger) + [tw] In case of "watch" option, check image only every 1/10 sec, instead of every 200us. This was way too short for devices like RasPi etc. (Hamish) + [tw] Leave jumping mode on invalid input and process input key as if it was entered in non jumping mode (Sergey Pinaev) qiv-3.0.1/contrib/gps2url0000775000175000001440000000250614774332451014167 0ustar andyusers#!/bin/bash # small script to extract GPS coordinates from an image and # call firefox with google maps url if the GPS info exists # # 2015-2023 Andy Spiegl - GPL # ORIGINAL IDEA (python version): 2012 Thomas Wiegner - GPL # my own program name self=$(basename $0) # defaults #BROWSER="firefox" BROWSER="sensible-browser" #MAPSURL="http://maps.google.de/maps?q=" MAPSURL="https://www.google.de/maps/place/" # syntax help Usage() { echo "Usage: $self [--browser ] [--mapsurl ] IMAGE_WITH_GPS_EXIFDATA" echo " [-h|--help]" echo "Extracts GPS data from image and calls Google maps in webbrowser." exit $1 } # process params while [ $# -gt 0 ] do case $1 in --browser) shift; BROWSER="$1"; shift; continue;; --mapsurl) shift; MAPSURL="$1"; shift; continue;; -h | --help) Usage 0;; -*) Usage 1;; *) imgfile="$1"; shift; continue;; esac break done # run exiftool to extract GPS coords COORDS=$( exiftool -t -GPSPosition -c "%d°%d'%.3f''" "$imgfile" | sed -e"s|.* ||" -e"s| ||g" ) #echo GPS coords in "$imgfile": $COORDS echo GPS coords: $COORDS # check for errors errstat=$? if [ $errstat != 0 ]; then echo "Error $errstat while calling exiftool and sed: $!" fi # send it to the webbrowser (avoid glib error messages) $BROWSER "${MAPSURL}${COORDS}" 2> /dev/null exit qiv-3.0.1/contrib/gps2url.py0000775000175000001440000000260414774332451014615 0ustar andyusers#!/usr/bin/python # coding=utf-8 # small script to extract GPS coordinates from an image and # call firefox with google maps url if the GPS info exists # 2012 Thomas Wiegner - GPL from PIL import Image from PIL.ExifTags import TAGS from subprocess import call import sys,os def get_exif(fn): if os.path.isfile(fn) : im = Image.open(fn) else : return -1 if im.format == "JPEG" : info = im._getexif() else : return 0 if info : for tag, value in info.items(): decoded = TAGS.get(tag, tag) if decoded == "GPSInfo" : return value return 0 if len(sys.argv) < 2 : print "Usage", sys.argv[0], "" exit(0) exif=get_exif(sys.argv[1]) if exif == 0: print "No GPS info available in image" exit(0) if exif == -1: print "File", sys.argv[1], "does not exist" exit(0) for k,v in exif.items(): if k == 1: lat_d = v if k == 3: lng_d = v if k == 2: lat_v = str(v[0][0]/v[0][1]) + unicode("°", "utf8") + str(v[1][0]/v[1][1]) + "'" + str(1.0* v[2][0]/v[2][1]) + "''" if k == 4: lng_v = str(v[0][0]/v[0][1]) + unicode("°", "utf8") + str(v[1][0]/v[1][1]) + "'" + str(1.0* v[2][0]/v[2][1]) + "''" try: lat_d and lng_d and lat_v and lng_v except NameError: print "No GPS location data defined" else: # make sure firefox is already running url="http://maps.google.de/maps?q="+lat_v+lat_d+lng_v+lng_d call(["firefox", url]) qiv-3.0.1/contrib/exiftool.tags.for.qiv-command0000664000175000001440000000155414774332451020355 0ustar andyusers-Artist -Copyright -Comment -Make -DeviceManufacturer -Model -DateTimeOriginal -ModifyDate -CreateDate -CameraTemperature -FileNumber -ImageSize -Aperture -ExposureTime -ISO -LightValue -FocalLength35efl -FocalLength35mm -FocalLengthIn35mmFormat -Lens35efl -DigitalZoom -DigitalZoomRatio -FOV -DOF -HyperfocalDistance -FocalLengthTeleZoom -FocusDistance -FocusDistanceLower -FocusDistanceUpper -AFAreaMode -AFPoint -NumAFPoints -ImageStabilization -Flash -CanonFlashMode -SelfTimer -Orientation -Categories -FacesDetected -TagsList -Subject -RegionName -ExposureProgram -CanonExposureMode -ShootingMode -EasyMode -SequenceNumber -MacroMode -FocusMode -MeteringMode -SpotMeteringMode -*Filter* -BurstShot -BurstSpeed -Software -CreatorTool -GPSPosition -GPSAltitude -GPSDateTime -GPSStatus -ControlMode -AutoExposureBracketing -AEBBracketValue -ICCProfileName -EncodingProcess qiv-3.0.1/contrib/exiftool.grep-exclude-pattern.for.qiv-command0000664000175000001440000000213214774332451023447 0ustar andyusers^Digital Zoom : None ^Digital Zoom Ratio : 1 ^Flash : Off, Did not fire ^Canon Flash Mode : Off ^Self Timer : Off ^Orientation : Horizontal (normal) ^Categories : (none) ^Faces Detected : 0 ^Shot Number In Continuous Burst : 1 ^Macro Mode : Normal ^Metering Mode : Unknown ^Exposure Program : Not Defined ^Fisheye Filter : Off ^ND Filter : Off ^Grainy B/W Filter : Off ^Soft Focus Filter : Off ^Toy Camera Filter : Off ^Miniature Filter : Off ^Miniature Filter Orientation : Unknown ^Miniature Filter Position : -1 ^Miniature Filter Parameter : -1 ^Painting Filter : Off ^Watercolor Filter : Off ^Control Mode : Camera Local Control ^Auto Exposure Bracketing : Off ^AEB Bracket Value : 0 ^Focal Length In 35mm Format : 0 mm qiv-3.0.1/xmalloc.c0000664000175000001440000000327114774332451013006 0ustar andyusers/* xmalloc.c - Do-or-die Memory management functions. * * Created by Kevin Locke (from numerous canonical examples) * * I hereby place this file in the public domain. It may be freely reproduced, * distributed, used, modified, built upon, or otherwise employed by anyone * for any purpose without restriction. */ #include #include #include #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 #endif void *xmalloc(size_t size) { void *allocated = malloc(size); if (allocated == NULL) { fprintf(stderr, "Error: Insufficient memory " # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) "(attempt to malloc %zu bytes)\n", size); #else "(attempt to malloc %u bytes)\n", (unsigned int) size); #endif exit(EXIT_FAILURE); } return allocated; } void *xcalloc(size_t num, size_t size) { void *allocated = calloc(num, size); if (allocated == NULL) { fprintf(stderr, "Error: Insufficient memory " # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) "(attempt to calloc %zu bytes)\n", size); #else "(attempt to calloc %u bytes)\n", (unsigned int) size); #endif exit(EXIT_FAILURE); } return allocated; } void *xrealloc(void *ptr, size_t size) { void *allocated; /* Protect against non-standard behavior */ if (ptr == NULL) { allocated = malloc(size); } else { allocated = realloc(ptr, size); } if (allocated == NULL) { fprintf(stderr, "Error: Insufficient memory " # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) "(attempt to realloc %zu bytes)\n", size); #else "(attempt to realloc %u bytes)\n", (unsigned int) size); #endif exit(EXIT_FAILURE); } return allocated; } qiv-3.0.1/xmalloc.h0000664000175000001440000000070514774332451013012 0ustar andyusers/* xmalloc.h - Header for do-or-die memory management functions. * * Created by Kevin Locke (to accompany xmalloc.c) * * I hereby place this file in the public domain. It may be freely reproduced, * distributed, used, modified, built upon, or otherwise employed by anyone * for any purpose without restriction. */ extern void *xmalloc(size_t size); extern void *xcalloc(size_t num, size_t size); extern void *xrealloc(void *ptr, size_t size); qiv-3.0.1/options.c0000664000175000001440000003560214774332451013045 0ustar andyusers/* Module : options.c Purpose : Read and evaluate command line options More : see qiv README Homepage : http://qiv.spiegl.de/ Original : http://www.klografx.net/qiv/ */ #include "qiv.h" #include #include #include #include #include #include #ifdef HAVE_GETOPT_LONG #include #else #include "lib/getopt.h" #endif #include "xmalloc.h" extern char *optarg; extern int optind, opterr, optopt; /* put longopt-only options to non ascii values */ #define LONGOPT_VIKEYS 256 #define LONGOPT_TRASHBIN 257 #define LONGOPT_ARTISTIGNORE 258 /* do NOT show artist name if it is this string */ #define LONGOPT_HIGHDPIFACTOR 259 /* resize everything by this factor */ static char *short_options = "ab:c:Cd:eEfg:hilLmno:pq:rstuvw:xyzA:BDF:GIJKMNPRSTW:X:Y:Z:"; static struct option long_options[] = { {"do_grab", 0, NULL, 'a'}, {"brightness", 1, NULL, 'b'}, {"contrast", 1, NULL, 'c'}, {"delay", 1, NULL, 'd'}, {"center", 0, NULL, 'e'}, {"fullscreen", 0, NULL, 'f'}, {"gamma", 1, NULL, 'g'}, {"help", 0, NULL, 'h'}, {"no_statusbar", 0, NULL, 'i'}, #if GDK_PIXBUF_MINOR >= 12 {"autorotate", 0, NULL, 'l'}, #endif {"maxpect", 0, NULL, 'm'}, {"no_filter", 0, NULL, 'n'}, {"bg_color", 1, NULL, 'o'}, {"transparency", 0, NULL, 'p'}, {"rotate", 1, NULL, 'q'}, {"random", 0, NULL, 'r'}, {"slide", 0, NULL, 's'}, {"scale_down", 0, NULL, 't'}, {"recursivedir", 0, NULL, 'u'}, {"followlinks", 0, NULL, 'L'}, {"version", 0, NULL, 'v'}, {"fixed_width", 1, NULL, 'w'}, {"root", 0, NULL, 'x'}, {"root_t", 0, NULL, 'y'}, {"root_s", 0, NULL, 'z'}, {"select_dir", 1, NULL, 'A'}, {"browse", 0, NULL, 'B'}, {"cycle", 0, NULL, 'C'}, {"no_sort", 0, NULL, 'D'}, {"showArtistName" , 0, NULL, 'E'}, {"file", 1, NULL, 'F'}, {"disable_grab", 0, NULL, 'G'}, {"statusbar", 0, NULL, 'I'}, {"showJPEGcomments", 0, NULL, 'J'}, {"mtime_sort", 0, NULL, 'K'}, {"merged_case_sort", 0, NULL, 'M'}, {"numeric_sort", 0, NULL, 'N'}, {"ignore_path_sort", 0, NULL, 'P'}, {"readonly", 0, NULL, 'R'}, {"shuffle", 0, NULL, 'S'}, {"watch", 0, NULL, 'T'}, {"fixed_zoom", 1, NULL, 'W'}, {"xineramascreen", 1, NULL, 'X'}, #ifdef SUPPORT_LCMS {"source_profile", 1, NULL, 'Y'}, {"display_profile", 1, NULL, 'Z'}, #endif {"trashbin", 0, NULL, LONGOPT_TRASHBIN}, {"vikeys", 0, NULL, LONGOPT_VIKEYS}, {"artist_ignore", 1, NULL, LONGOPT_ARTISTIGNORE}, {"highDPIfactor", 1, NULL, LONGOPT_HIGHDPIFACTOR}, {0, 0, NULL, 0} }; static int mtime_sort = 0, numeric_sort = 0, merged_case_sort = 0, ignore_path_sort = 0; /* This array makes it easy to sort filenames into merged-case order * (e.g. AaBbCcDdEeFf...). */ static unsigned char casemap[256] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, 0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, 0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, 0x40,0x41,0x43,0x45,0x47,0x49,0x4B,0x4D, /* @ABCDEFG */ 0x4F,0x51,0x53,0x55,0x57,0x59,0x5B,0x5D, /* HIJKLMNO */ 0x5F,0x61,0x63,0x65,0x67,0x69,0x6B,0x6D, /* PQRSTUVW */ 0x6F,0x71,0x73,0x75,0x76,0x77,0x78,0x79, /* XYZ[\]^_ */ 0x7A,0x42,0x44,0x46,0x48,0x4A,0x4C,0x4E, /* `abcdefg */ 0x50,0x52,0x54,0x56,0x58,0x5A,0x5C,0x5E, /* hijklmno */ 0x60,0x62,0x64,0x66,0x68,0x6A,0x6C,0x6E, /* pqrstuvw */ 0x70,0x72,0x74,0x7B,0x7C,0x7D,0x7E,0x7F, /* xyz{|}~ */ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97, 0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7, 0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7, 0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7, 0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7, 0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7, 0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7, 0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF }; static time_t get_mtime(unsigned char *fn) { struct stat attrib; if(stat((char *) fn, &attrib) == 0) return attrib.st_mtime; return 0; } static int my_strcmp(const void *v1, const void *v2) { unsigned char *cp1 = *(unsigned char **)v1; unsigned char *cp2 = *(unsigned char **)v2; unsigned char *sufptr1, *sufptr2; int tmp; sufptr1 = cp1 + strlen((char *)cp1); while (--sufptr1 > cp1 && *sufptr1 != '.') {} sufptr2 = cp2 + strlen((char *)cp2); while (--sufptr2 > cp2 && *sufptr2 != '.') {} if(mtime_sort) { time_t diff = get_mtime(cp1) - get_mtime(cp2); if(diff < 0) return -1; if(diff > 0) return 1; // fall through in case of same time stamp } if (ignore_path_sort) { unsigned char *slash; if ((slash = (unsigned char *)strrchr((char *)cp1, '/')) != NULL) cp1 = slash + 1; if ((slash = (unsigned char *)strrchr((char *)cp2, '/')) != NULL) cp2 = slash + 1; } if (numeric_sort) { int namelen = 0, diff = 0; do { if (sufptr1 && (isdigit(*cp1) || isdigit(*cp2))) { unsigned char *ep1, *ep2; if (diff) return diff; for (ep1 = cp1; isdigit(*ep1); ep1++) {} if (ep1 == cp1) return 1; for (ep2 = cp2; isdigit(*ep2); ep2++) {} if (cp2 == ep2) return -1; if ((diff = (ep1 - cp1) - (ep2 - cp2)) == 0) { long val = atol((char *)cp1) - atol((char *)cp2); diff = val < 0? -1 : val > 0? 1 : 0; } if (diff && sufptr1 - cp1 <= namelen && sufptr2 - cp2 <= namelen) return diff; namelen += ep1 - cp1; cp1 = ep1; cp2 = ep2 - 1; } else { if (cp1 == sufptr1) { if (cp2 != sufptr2) return -1; sufptr1 = sufptr2 = NULL; } else if (cp2 == sufptr2) return 1; if (merged_case_sort) tmp = casemap[*cp1++] - casemap[*cp2]; else tmp = *cp1++ - *cp2; if (tmp != 0) return tmp; if (*cp2 == '/') namelen = 0; else namelen++; } } while (*cp2++ != '\0'); return diff; } do { if (cp1 == sufptr1) { if (cp2 != sufptr2) return -1; } else if (cp2 == sufptr2) return 1; if (merged_case_sort) tmp = casemap[*cp1++] - casemap[*cp2]; else tmp = *cp1++ - *cp2; if (tmp != 0) return tmp; } while (*cp2++ != '\0'); return 0; } void options_read(int argc, char **argv, qiv_image *q) { int long_index, shuffle = 0, need_sort = 1; int c, cnt; int force_statusbar=-1; /* default is don't force */ struct stat sb; while ((c = getopt_long(argc, argv, short_options, long_options, &long_index)) != -1) { switch(c) { case 'a': do_grab=1; break; case 'b': q->mod.brightness = (checked_atoi(optarg)+32)*8; if ((q->mod.brightness<0) || (q->mod.brightness>512)) usage(argv[0],1); break; case 'c': q->mod.contrast = (checked_atoi(optarg)+32)*8; if ((q->mod.contrast<0) || (q->mod.contrast>512)) usage(argv[0],1); break; case 'd': delay=(int) (checked_atof(optarg) * 1000); if (delay < 0) { g_print("Error: %s is an invalid slide show delay.\n",optarg); exit(1); } else if (delay == 0) /* make sure we get the "quit key" */ do_grab = 1; break; case 'e': center=0; break; case 'f': fullscreen=1; break; case 'g': q->mod.gamma = (checked_atoi(optarg)+32)*8; if ((q->mod.gamma<0) || (q->mod.gamma>512)) usage(argv[0],1); break; case 'h': show_help(argv[0], 0); break; case 'i': force_statusbar=0; break; #if GDK_PIXBUF_MINOR >= 12 case 'l': autorotate=0; /* turn autorotation OFF, default is ON */ break; #endif case 'm': maxpect=1; break; case 'n': filter=0; break; /* case 'o': image_bg_spec = optarg; break;*/ case 'p': transparency=1; break; case 'q': rotation=checked_atoi(optarg); if (rotation < 0 || (rotation > 3 && rotation != 11 && rotation != 13)) usage(argv[0],1); break; case 'r': random_order=1; break; case 's': slide=1; break; case 't': scale_down=1; break; case 'u': recursive = 1; break; case 'L': followlinks=1; break; case 'v': g_print("qiv (Quick Image Viewer) v%s\n", VERSION); exit(0); break; case 'w': q->win_w = fixed_window_size = checked_atoi(optarg); break; case 'x': to_root=1; break; case 'y': to_root_t=1; break; case 'z': to_root_s=1; break; case 'A': snprintf(select_dir, sizeof select_dir, "%s", optarg); break; case 'B': browse=1; break; case 'C': cycle=1; break; case 'D': need_sort = 0; break; case 'E': artist_window=1; break; case 'F': if(rreadfile(optarg) < 0) { g_print("Error: %s could not be opened: %s.\n",optarg, strerror(errno)); exit(1); } break; case 'G': disable_grab=1; break; case 'I': force_statusbar=1; break; case 'J': comment_window=1; break; case 'K': mtime_sort = 1; break; case 'M': merged_case_sort = 1; break; case 'N': numeric_sort = 1; break; case 'P': ignore_path_sort = 1; break; case 'R': readonly=1; break; case 'S': shuffle=1; need_sort=0; break; case 'T': watch_file=1; break; case 'W': fixed_zoom_factor = (checked_atoi(optarg) - 100) / 10; zoom_factor = fixed_zoom_factor; break; case 'X': user_screen = checked_atoi(optarg); // g_print("set xinerama screen: %i\n", user_screen); break; #ifdef SUPPORT_LCMS case 'Y': source_profile = optarg; cms_transform = 1; break; case 'Z': display_profile = optarg; cms_transform = 1; break; #endif case LONGOPT_TRASHBIN: trashbin=1; break; case LONGOPT_VIKEYS: vikeys=1; break; case LONGOPT_ARTISTIGNORE: artist_ignore=optarg; break; case LONGOPT_HIGHDPIFACTOR: highDPIfactor=checked_atof(optarg); if (highDPIfactor <= 0) { g_print("Error: %s is not a valid zoom factor.\n",optarg); exit(1); } break; case 0: case '?': usage(argv[0], 1); exit(0); } } /* In case user specified -D and -K, -P, -M, or -N */ need_sort = need_sort | mtime_sort | ignore_path_sort | merged_case_sort | numeric_sort; /* default: show statusbar only in fullscreen mode */ /* user wants to override? */ if (force_statusbar != -1) { statusbar_window=statusbar_fullscreen = force_statusbar; } if((cnt = argc - optind) > 0) { if (!images) { max_image_cnt = 8192; image_names = (char**)xmalloc(max_image_cnt * sizeof(char*)); } while (cnt-- > 0) { if (stat(argv[optind], &sb) >= 0 && S_ISDIR(sb.st_mode)) { rreaddir(argv[optind++],recursive); } else { if (images >= max_image_cnt) { max_image_cnt += 8192; image_names = (char**)xrealloc(image_names, max_image_cnt*sizeof(char*)); } image_names[images++] = argv[optind++]; } } } if(shuffle) { char *fn; int i, p; for (i=0;i screen */ int recursive; /* descend recursively */ int followlinks; /* follow symlinks to dirs */ int to_root; /* display on root (centered) */ int to_root_t; /* display on root (tiled) */ int to_root_s; /* display on root (stretched) */ int transparency; /* transparency on/off */ int do_grab; /* grab keboard/pointer (default off) */ int disable_grab; /* disable keyboard/mouse grabbing in fullscreen mode */ int max_rand_num; /* the largest random number range we will ask for */ int fixed_window_size = 0; /* window with fixed size (default off) */ int fixed_zoom_factor = 0; /* fixed zoom factor (percentage) (default off) */ int zoom_factor = 0; /* zoom factor */ float highDPIfactor = 1.0; /* resize all images by this factor to compensate for high (or low) DPI screens */ int watch_file = 0; /* watch current files Timestamp, reload if changed */ int magnify = 0; /* [lc] */ int user_screen = 0; /* preferred (by user) monitor */ int browse = 0; /* scan directory of file for browsing */ int autorotate = 1; /* autorotate JPEGs according to EXIF tag */ int rotation = 0; /* rotation x degrees clockwise, 1=90degrees 2=180degrees 3=270degrees */ int vikeys = 0; /* option to give us some vi-like keys (for movement) */ int trashbin = 0; /* option to use users trash bin instead of local .qiv_trash when deleting image */ char *artist_ignore = ""; /* option to NOT show artist info if it is equal to this string */ #ifdef SUPPORT_LCMS const char* source_profile = NULL; const char* display_profile = NULL; cmsHPROFILE h_source_profile; cmsHPROFILE h_display_profile; cmsHTRANSFORM h_cms_transform; int cms_transform = 0; #endif /* Used for the ? key */ const char *helpstrs[] = { VERSION_FULL, "", "space/left mouse/wheel right next picture", "backspace/right mouse/wheel left previous picture", "PgDn/wheel down 5 pictures forward", "PgUp/wheel up 5 pictures backward", "q/ESC/middle mouse exit", "", "0-9 Run 'qiv-command '", "^ Run 'qiv-command ^ '", "?/F1 show keys (in fullscreen mode)", "F11/F12 in/decrease slideshow delay (1 second)", "a copy current image to .qiv-select", "A artist (author) info on/off", "d/D/del move picture to .qiv-trash (to trash bin with --trashbin option)", "u undelete the previously trashed image", "+/=/mouse btn 9 zoom in (10% / +50% if above 100%)", "-/mouse btn 8 zoom out (10%)", "e center mode on/off", "f fullscreen mode on/off", "m scale to screen size on/off", "t scale down on/off", "X cycle through monitors", "s slide show on/off", "p transparency on/off", "r random order on/off", "b - brightness", "B + brightness", "c - contrast", "C + contrast", "g - gamma", "G + gamma", "o reset brightness, contrast, gamma", "h flip horizontal", "v flip vertical", "k rotate right", "l rotate left", "jtx jump to image number x", "jfx jump forward x images", "jbx jump backward x images", "enter/return reset zoom, rotation and color settings", #ifdef HAVE_EXIF "E display Exif information", #endif "i statusbar on/off", "J JPEG comments on/off", "I iconify window", "w watch file on/off", "x center image on background", "y tile image on background", "z stretch image on background", ", grab on/off", "< turn on/off magnifying window", "arrow keys/wheel move image (in fullscreen mode)", "arrow keys/wheel+Shift move image faster (in fullscreen mode)", "NumPad-arrow keys+NumLock move image faster (in fullscreen mode)", NULL }; /* For --help output, we'll skip the first two lines. */ const char **helpkeys = helpstrs+2; /* Used for filtering */ const char *image_extensions[] = { #ifdef EXTN_JPEG ".jpg",".jpeg", ".jpe", #endif #ifdef EXTN_GIF ".gif", #endif #ifdef EXTN_TIFF ".tif",".tiff", #endif #ifdef EXTN_XPM ".xpm", #endif #ifdef EXTN_PNG ".png",".pjpeg", #endif #ifdef EXTN_PPM ".ppm", #endif #ifdef EXTN_PNM ".pnm", #endif #ifdef EXTN_PGM ".pgm", ".pbm", #endif #ifdef EXTN_PCX ".pcx", #endif #ifdef EXTN_BMP ".bmp", #endif #ifdef EXTN_EIM ".eim", #endif #ifdef EXTN_TGA ".tga", #endif #ifdef EXTN_ICO ".ico", #endif #ifdef EXTN_WMF ".wmf", #endif #ifdef EXTN_SVG ".svg", #endif #ifdef EXTN_WEBP ".webp", #endif #ifdef EXTN_HEIF ".heic", ".heif", #endif NULL }; #ifdef HAVE_MAGIC const char *image_magic[] = { #ifdef EXTN_JPEG "JPEG image data", #endif #ifdef EXTN_GIF "GIF image data", #endif #ifdef EXTN_TIFF "TIFF image data", #endif #ifdef EXTN_XPM "X pixmap image", #endif #ifdef EXTN_PNG "PNG image data", #endif #ifdef EXTN_PGM "Netpbm PBM", "Netpbm PPM", #endif #ifdef EXTN_BMP "PC bitmap data", #endif #ifdef EXTN_TGA "Targa image data", #endif #ifdef EXTN_PCX "PCX ver. 3.0 image", #endif #ifdef EXTN_SVG "SVG Scalable Vector", #endif #ifdef EXTN_ICO "MS Windows icon resource", #endif #ifdef EXTN_WEBP "RIFF (little-endian) data, Web/P image", #endif #ifdef EXTN_HEIF "ISO Media, HEIF Image", #endif NULL }; #endif #endif /* MAIN_H */ qiv-3.0.1/image.c0000664000175000001440000010052014774332451012424 0ustar andyusers/* Module : image.c Purpose : Routines dealing with image display More : see qiv README Policy : GNU GPL Homepage : http://qiv.spiegl.de/ Original : http://www.klografx.net/qiv/ */ #include #include #include #include #include #include #include #include "qiv.h" #include "xmalloc.h" #include "qiv.xpm" static void setup_win(qiv_image *); //static void setup_magnify(qiv_image *, qiv_mgl *); // [lc] static int used_masks_before=0; static struct timeval load_before, load_after; static double load_elapsed; static GdkCursor *cursor, *visible_cursor, *invisible_cursor; int img_from_pixbuf_loader(char * image_name, int * has_alpha, GError ** err, qiv_image *q) { GError *error=NULL; GdkPixbuf *pixbuf_ori = NULL; GdkPixbuf *pixbuf = NULL; guchar * pixeldata = NULL; int pb_w, pb_h; const gchar *gdk_orientation = NULL; #ifdef SUPPORT_LCMS char *icc_profile; cmsHPROFILE h_emb_profile; cmsHTRANSFORM h_emb_transform; #endif pixbuf_ori = gdk_pixbuf_new_from_file(image_name, &error); if (error != NULL) { *err=error; q->pb = NULL; return -1; } *has_alpha = gdk_pixbuf_get_has_alpha(pixbuf_ori); #if GDK_PIXBUF_MINOR >= 12 if(autorotate) { gdk_orientation = gdk_pixbuf_get_option(pixbuf_ori, "orientation"); if(gdk_orientation) { #ifdef DEBUG printf("orientation %s\n", gdk_orientation); #endif pixbuf = gdk_pixbuf_apply_embedded_orientation(pixbuf_ori); g_object_unref(pixbuf_ori); pixbuf_ori = pixbuf; } } #else #warning autoration needs at least gdk version 2.12 #endif #ifdef SUPPORT_LCMS pixeldata = gdk_pixbuf_get_pixels(pixbuf_ori); pb_w = gdk_pixbuf_get_width(pixbuf_ori); pb_h = gdk_pixbuf_get_height(pixbuf_ori); if((icc_profile=get_icc_profile(image_name))) { #ifdef DEBUG g_print("has color profile\n"); #endif h_emb_profile = cmsOpenProfileFromMem(icc_profile+sizeof(cmsUInt32Number), *(cmsUInt32Number *)icc_profile); if(h_display_profile==NULL) { h_display_profile = cmsCreate_sRGBProfile(); } if (*has_alpha == 0) { h_emb_transform = cmsCreateTransform(h_emb_profile, TYPE_RGB_8, h_display_profile, TYPE_RGB_8, INTENT_PERCEPTUAL, 0); } else { h_emb_transform = cmsCreateTransform(h_emb_profile, TYPE_RGBA_8, h_display_profile, TYPE_RGBA_8, INTENT_PERCEPTUAL, 0); } if(h_emb_transform) { cmsDoTransform(h_emb_transform, pixeldata, pixeldata, pb_w*pb_h); cmsCloseProfile(h_emb_profile); cmsDeleteTransform(h_emb_transform); } else { printf("qiv warning: %s contains corrupt color profile\n",image_name); } free(icc_profile); } /* do the color transform */ else if (cms_transform && h_cms_transform) { cmsDoTransform(h_cms_transform, pixeldata, pixeldata, pb_w*pb_h); } #endif #ifdef HAVE_EXIF artist = get_exif_artist(image_name); //printf("DEBUG: Artist: %s\n", artist); #endif q->pb = gdk_pixbuf_copy(pixbuf_ori); g_object_unref(pixbuf_ori); return 0; } // small wrapper around pixbuf and imlib loader int load_image(char* image_name, int* has_alpha, qiv_image *q) { //Imlib_Image * im = NULL; int im; GError * error = NULL; im = img_from_pixbuf_loader(image_name, has_alpha, &error, q); if(im != 0 && error != NULL) { // Report GDK error to user if imlib failed, too fprintf(stderr, "Unable to read file: %s\n", error->message); } if(error != NULL) { // free error g_error_free (error); } return im; } /* * Load & display image */ void qiv_load_image(qiv_image *q) { struct stat statbuf; const char * image_name = image_names[ image_idx]; //Imlib_Image * im=NULL; int im=0; int has_alpha=0, rot; q->exposed=0; gettimeofday(&load_before, 0); stat(image_name, &statbuf); current_mtime = statbuf.st_mtime; file_size = statbuf.st_size; #ifdef DEBUG g_print("loading %s\n",image_name); #endif im = load_image((char*)image_name, &has_alpha, q); if (im) { /* error */ q->error = 1; q->orig_w = 400; q->orig_h = 300; } else { /* Retrieve image properties */ q->error = 0; q->orig_w = gdk_pixbuf_get_width(q->pb); q->orig_h = gdk_pixbuf_get_height(q->pb); if (rotation > 10) { /* conditional rotation -- apply rotation only if image fits better */ int screen_is_wide = monitor[q->mon_id].width > monitor[q->mon_id].height; int image_is_wide = q->orig_w > q->orig_h; int does_not_fit = q->orig_w > monitor[q->mon_id].width || q->orig_h > monitor[q->mon_id].height; if (screen_is_wide != image_is_wide && does_not_fit) rot = rotation - 10; /* we want the rotation (will be 11 -> 1 or 13 -> 3) */ else rot = 0; /* don't rotate */ } else rot = rotation; if (rot) { if (rot != 2) { swap(&q->orig_w, &q->orig_h); swap(&q->win_w, &q->win_h); } } if (rot && rot != 2) correct_image_position(q); } if (first) { setup_win(q); } check_size(q, TRUE); /* desktop-background -> exit */ if (to_root || to_root_t || to_root_s) { if (!im) { fprintf(stderr, "qiv: cannot load background_image\n"); qiv_exit(1); } set_desktop_image(q); qiv_exit(0); } // This does not seem to be needed /*gdk_window_set_background(q->win, im ? &image_bg : &error_bg);*/ /*printf("set background\n");*/ gettimeofday(&load_after, 0); load_elapsed = ((load_after.tv_sec + load_after.tv_usec / 1.0e6) - (load_before.tv_sec + load_before.tv_usec / 1.0e6)); update_image(q, FULL_REDRAW); // if (magnify && !fullscreen) { // [lc] // setup_magnify(q, &magnify_img); // update_magnify(q, &magnify_img, FULL_REDRAW, 0, 0); // } } static void setup_win(qiv_image *q) { GdkWindowAttr attr; static GList icon_list = {NULL, NULL, NULL}; /*TODO: thw 25.5.24: should that even be here?*/ //destroy_image(q); if (!fullscreen) { attr.window_type=GDK_WINDOW_TOPLEVEL; attr.wclass=GDK_INPUT_OUTPUT; attr.event_mask=GDK_ALL_EVENTS_MASK; attr.x = center ? q->win_x : 0; attr.y = center ? q->win_y : 0; attr.width = q->win_w; attr.height = q->win_h; q->win = gdk_window_new(NULL, &attr, GDK_WA_X|GDK_WA_Y); if (center) { GdkGeometry geometry = { .min_width = q->win_w, .min_height = q->win_h, .max_width = q->win_w, .max_height = q->win_h, .win_gravity = GDK_GRAVITY_STATIC }; gdk_window_set_geometry_hints(q->win, &geometry, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE | GDK_HINT_WIN_GRAVITY); gdk_window_move_resize(q->win, q->win_x, q->win_y, q->win_w, q->win_h); } else { GdkGeometry geometry = { .min_width = q->win_w, .min_height = q->win_h, .max_width = q->win_w, .max_height = q->win_h, }; gdk_window_set_geometry_hints(q->win, &geometry, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); gdk_window_resize(q->win, q->win_w, q->win_h); } if (!(to_root || to_root_t || to_root_s)) gdk_window_lower(q->win); } else { /* fullscreen */ attr.window_type=GDK_WINDOW_TOPLEVEL; attr.wclass=GDK_INPUT_OUTPUT; attr.event_mask=GDK_ALL_EVENTS_MASK; // attr.x = 0; // attr.y = 0; attr.x = monitor[q->mon_id].x; attr.y = monitor[q->mon_id].y; // printf("mon_id %d \n",q->mon_id); attr.width=monitor[q->mon_id].width; attr.height=monitor[q->mon_id].height; // q->win = gdk_window_new(NULL, &attr, GDK_WA_X|GDK_WA_Y|GDK_WA_TYPE_HINT); q->win = gdk_window_new(NULL, &attr, GDK_WA_X|GDK_WA_Y); gdk_window_set_cursor(q->win, cursor); if (!(to_root || to_root_t || to_root_s)) { gdk_window_fullscreen(q->win); gdk_window_show(q->win); } } /* this is all done only once */ if(icon_list.data==NULL) { icon_list.data = gdk_pixbuf_new_from_xpm_data(qiv_icon); invisible_cursor = gdk_cursor_new_for_display(gdk_display_get_default(), GDK_BLANK_CURSOR); cursor = visible_cursor = gdk_cursor_new_for_display(gdk_display_get_default(), CURSOR); } gdk_window_set_icon_list(q->win, &icon_list); gdk_window_set_cursor(q->win, cursor); //setup_imlib_for_drawable(GDK_DRAWABLE(q->win)); } void hide_cursor(qiv_image *q) { if (cursor != invisible_cursor) gdk_window_set_cursor(q->win, cursor = invisible_cursor); } void show_cursor(qiv_image *q) { if (cursor != visible_cursor) gdk_window_set_cursor(q->win, cursor = visible_cursor); } /* set image as background */ void set_desktop_image(qiv_image *q) { GdkWindow *root_win = gdk_get_default_root_window(); #if GDK_MAJOR_VERSION < 3 GdkPixmap *pixmap; GdkBitmap *mask = NULL; gint root_w = screen_x, root_h = screen_y; gint root_x = 0, root_y = 0; if (to_root || to_root_t) { root_w = q->win_w; root_h = q->win_h; } if (to_root) { root_x = (screen_x - root_w) / 2; root_y = (screen_y - root_h) / 2; } #ifdef DEBUG if (mask) g_print("*** image has transparency\n"); #endif gdk_window_clear(root_win); if (to_root_t) { gdk_pixbuf_render_pixmap_and_mask_for_colormap (q->pb, gdk_window_get_colormap(q->win), &pixmap, &mask, 128); gdk_window_set_back_pixmap(root_win, pixmap, FALSE); printf("to root_t\n"); } else { printf("to root x %d y %d w %d h %d\n", root_x, root_y, root_w, root_h); GdkPixbuf* pb_tmp; if (to_root_s){ if (gdk_pixbuf_get_has_alpha(q->pb)){ pb_tmp = gdk_pixbuf_scale_simple(q->pb, screen_x, screen_y, GDK_INTERP_BILINEAR); } else { pb_tmp = gdk_pixbuf_composite_color_simple(q->pb, screen_x, screen_y, GDK_INTERP_BILINEAR, 255, 0x08, 0x00666666, 0x00aaaaaa); } } else { pb_tmp = gdk_pixbuf_new(GDK_COLORSPACE_RGB, gdk_pixbuf_get_has_alpha(q->pb), 8, screen_x, screen_y); gdk_pixbuf_copy_area(q->pb, 0, 0, q->win_w, q->win_h, pb_tmp, root_x, root_y); } gdk_pixbuf_render_pixmap_and_mask_for_colormap (pb_tmp, gdk_window_get_colormap(q->win), &pixmap, &mask, 128); gdk_window_set_back_pixmap(root_win, pixmap, FALSE); g_object_unref(pb_tmp); } gdk_window_clear(root_win); gdk_display_flush(gdk_display_get_default()); #endif } void zoom_in(qiv_image *q) { int zoom_percentage; int w_old, h_old; /* first compute current zoom_factor */ if (maxpect || scale_down || fixed_window_size) { zoom_percentage=myround((1.0-(q->orig_w - q->win_w)/(double)q->orig_w)*100 / highDPIfactor); zoom_factor=(zoom_percentage - 100) / 10; } maxpect = scale_down = 0; // zoom in faster if above 100% if (zoom_factor < 0) { zoom_factor++; } else { zoom_factor += 5; } w_old = q->win_w; h_old = q->win_h; q->win_w = (gint)(q->orig_w * (1 + zoom_factor * 0.1) * highDPIfactor); q->win_h = (gint)(q->orig_h * (1 + zoom_factor * 0.1) * highDPIfactor); /* adapt image position */ q->win_x -= (q->win_w - w_old) / 2; q->win_y -= (q->win_h - h_old) / 2; if (fullscreen) { if (center) center_image(q); else correct_image_position(q); } else { correct_image_position(q); } } void zoom_out(qiv_image *q) { int zoom_percentage; int w_old, h_old; /* first compute current zoom_factor */ if (maxpect || scale_down || fixed_window_size) { zoom_percentage=myround((1.0-(q->orig_w - q->win_w)/(double)q->orig_w)*100 / highDPIfactor); zoom_factor=(zoom_percentage - 100) / 10; } maxpect = scale_down = 0; w_old = q->win_w; h_old = q->win_h; if(zoom_factor > -9 && q->win_w > MIN(64, q->orig_w) && q->win_h > MIN(64, q->orig_h)) { zoom_factor--; q->win_w = (gint)(q->orig_w * (1 + zoom_factor * 0.1) * highDPIfactor); q->win_h = (gint)(q->orig_h * (1 + zoom_factor * 0.1) * highDPIfactor); /* adapt image position */ q->win_x -= (q->win_w - w_old) / 2; q->win_y -= (q->win_h - h_old) / 2; if (fullscreen) { if (center) center_image(q); else correct_image_position(q); } else { correct_image_position(q); } } else { snprintf(infotext, sizeof infotext, "(Cannot zoom out more)"); fprintf(stderr, "qiv: cannot zoom out more\n"); } } void zoom_maxpect(qiv_image *q) { double zx = (double)monitor[q->mon_id].width / (double)q->orig_w; double zy = (double)monitor[q->mon_id].height / (double)q->orig_h; /* titlebar and frames ignored on purpose to use full height/width of screen */ q->win_w = (gint)(q->orig_w * MIN(zx, zy)); q->win_h = (gint)(q->orig_h * MIN(zx, zy)); center_image(q); } /* Set display settings to startup values which are used whenever a new image is loaded. */ void reload_image(qiv_image *q) { int im; int has_alpha = 0; //imlib_image_set_changes_on_disk(); im = load_image(image_names[image_idx], &has_alpha, q); if (im && watch_file) return; struct stat statbuf; stat(image_names[image_idx], &statbuf); current_mtime = statbuf.st_mtime; if (im!=0) { q->error = 1; q->orig_w = 400; q->orig_h = 300; } else { /* Retrieve image properties */ q->error = 0; q->orig_w = gdk_pixbuf_get_width(q->pb); q->orig_h = gdk_pixbuf_get_height(q->pb); } q->win_w = (gint)(q->orig_w * (1 + zoom_factor * 0.1) * highDPIfactor); q->win_h = (gint)(q->orig_h * (1 + zoom_factor * 0.1) * highDPIfactor); reset_mod(q); if (center) center_image(q); } void check_size(qiv_image *q, gint reset) { if (maxpect || (scale_down && (q->orig_w*highDPIfactor>monitor[q->mon_id].width || q->orig_h*highDPIfactor>monitor[q->mon_id].height))) { zoom_maxpect(q); } else if (reset || (scale_down && (q->win_worig_w*highDPIfactor || q->win_horig_h*highDPIfactor))) { reset_coords(q); } if (center){ center_image(q); } else if (fullscreen) { if (q->win_x > monitor[q->mon_id].x) q->win_x -= monitor[q->mon_id].x; if (q->win_y > monitor[q->mon_id].y) q->win_y -= monitor[q->mon_id].y; } else { if (q->win_x < monitor[q->mon_id].x) q->win_x += monitor[q->mon_id].x; if (q->win_y < monitor[q->mon_id].y) q->win_y += monitor[q->mon_id].y; } } void reset_coords(qiv_image *q) { if (fixed_window_size) { double w_o_ratio = (double)(fixed_window_size) / q->orig_w; q->win_w = fixed_window_size; q->win_h = q->orig_h * w_o_ratio; } else { q->win_w = (gint)(q->orig_w * (1 + zoom_factor * 0.1) * highDPIfactor); q->win_h = (gint)(q->orig_h * (1 + zoom_factor * 0.1) * highDPIfactor); } } /* Something changed the image. Redraw it. */ void update_image(qiv_image *q, int mode) { //static GdkPixmap * m = NULL; //Pixmap x_pixmap, x_mask; #if GDK_MAJOR_VERSION < 3 GdkBitmap *mask = NULL; #endif double elapsed=0; int i; cairo_t *cr; if (q->error) { g_snprintf(q->win_title, sizeof q->win_title, "qiv: ERROR! cannot load image: %s", image_names[image_idx]); gdk_display_beep(gdk_display_get_default()); /* take this image out of the file list */ --images; for(i=image_idx;iwin_title, sizeof q->win_title, "qiv: %s (%dx%d) %d%% [%d/%d] b%d/c%d/g%d %s", image_names[image_idx], q->orig_w, q->orig_h, myround( (1.0-(q->orig_w - q->win_w)/(double)q->orig_w)*100 / highDPIfactor ), image_idx+1, images, q->mod.brightness/8-32, q->mod.contrast/8-32, q->mod.gamma/8-32, infotext); snprintf(infotext, sizeof infotext, "(-)"); } // mode == MOVED else { #ifdef DEBUG if (gdk_pixbuf_get_has_alpha(q->pb)) g_print("*** image has transparency\n"); #endif g_snprintf(q->win_title, sizeof q->win_title, "qiv: %s (%dx%d) %d%% [%d/%d] b%d/c%d/g%d %s %1.01fs", image_names[image_idx], q->orig_w, q->orig_h, myround( (1.0-(q->orig_w - q->win_w)/(double)q->orig_w)*100 / highDPIfactor ), image_idx+1, images, q->mod.brightness/8-32, q->mod.contrast/8-32, q->mod.gamma/8-32, infotext, load_elapsed+elapsed); snprintf(infotext, sizeof infotext, "(-)"); } } gdk_window_set_title(q->win, q->win_title); q->text_len = strlen(q->win_title); pango_layout_set_text(layout, q->win_title, -1); pango_layout_get_pixel_size (layout, &(q->text_w), &(q->text_h)); if(comment && comment_window) { pango_layout_set_text(layoutComment, comment, -1); pango_layout_get_pixel_size (layoutComment, &(q->comment_w), &(q->comment_h)); } if(artist && artist_window && strcmp(artist, artist_ignore)) { pango_layout_set_text(layoutArtist, artist, -1); pango_layout_get_pixel_size (layoutArtist, &(q->artist_w), &(q->artist_h)); } if (!fullscreen) { #if GDK_MAJOR_VERSION < 3 gdk_window_clear(q->win); #endif GdkGeometry geometry = { .min_width = q->win_w, .min_height = q->win_h, .max_width = q->win_w, .max_height = q->win_h, .win_gravity = GDK_GRAVITY_STATIC }; gdk_window_set_geometry_hints(q->win, &geometry, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE | GDK_HINT_WIN_GRAVITY); if(first) { gdk_window_show(q->win); first = 0; q->exposed=0; } if(mode != MIN_REDRAW) gdk_window_move_resize(q->win, q->win_x, q->win_y, q->win_w, q->win_h); if (!q->error) { //gdk_window_set_back_pixmap(q->win, q->p, FALSE); cr = gdk_cairo_create(q->win); GdkPixbuf* pb_tmp; if (gdk_pixbuf_get_n_channels(q->pb) == 3){ pb_tmp = gdk_pixbuf_scale_simple(q->pb, q->win_w, q->win_h, GDK_INTERP_BILINEAR); } else { GdkPixbuf* pb_tmp2; pb_tmp2 = gdk_pixbuf_scale_simple(q->pb, q->win_w, q->win_h, GDK_INTERP_BILINEAR); #if GDK_MAJOR_VERSION < 3 gdk_pixbuf_render_pixmap_and_mask_for_colormap (pb_tmp2, gdk_window_get_colormap(q->win), NULL, &mask, 128); #endif pb_tmp = gdk_pixbuf_composite_color_simple(q->pb, q->win_w, q->win_h, GDK_INTERP_BILINEAR, 255, 0x08, 0x00666666, 0x00aaaaaa); g_object_unref(pb_tmp2); } gdk_cairo_set_source_pixbuf (cr, pb_tmp, 0, 0); //cairo_rectangle(cr, 0, 0, q->win_w, q->win_h); cairo_paint(cr); cairo_destroy(cr); /* remove or set transparency mask */ if (used_masks_before) { if (transparency) { #if GDK_MAJOR_VERSION < 3 gdk_window_shape_combine_mask(q->win, mask, 0, 0); #else // GDK3 Code cairo_surface_t *surface; cairo_t *cr_m; cairo_region_t *region; surface = cairo_image_surface_create (CAIRO_FORMAT_A1, q->win_w, q->win_h); cr_m = cairo_create(surface); gdk_cairo_set_source_pixbuf (cr_m, q->pb, 0, 0); cairo_paint(cr_m); region = gdk_cairo_region_create_from_surface (surface); gdk_window_shape_combine_region(q->win, region, 0, 0); cairo_destroy(cr_m); printf("combine shape\n"); #endif } else { #if GDK_MAJOR_VERSION < 3 gdk_window_shape_combine_mask(q->win, 0, 0, 0); #endif used_masks_before = 0; } } else { if (transparency && (gdk_pixbuf_get_n_channels(q->pb) == 4)) { #if GDK_MAJOR_VERSION < 3 gdk_window_shape_combine_mask(q->win, mask, 0, 0); #else // GDK3 Code cairo_surface_t *surface; cairo_t *cr_m; cairo_region_t *region; surface = cairo_image_surface_create (CAIRO_FORMAT_A1, q->win_w, q->win_h); cr_m = cairo_create(surface); gdk_cairo_set_source_pixbuf (cr_m, q->pb, 0, 0); cairo_paint(cr_m); cairo_destroy(cr_m); region = gdk_cairo_region_create_from_surface (surface); gdk_window_shape_combine_region(q->win, region, 0, 0); printf("combine shape\n"); #endif used_masks_before=1; } } g_object_unref(pb_tmp); } //printf("----\n"); //gdk_window_clear(q->win); if(statusbar_window) { #ifdef DEBUG g_print("*** print statusbar at (%d, %d)\n", MAX(2,q->win_w-q->text_w-10), MAX(2,q->win_h-q->text_h-10)); #endif cr = gdk_cairo_create (q->win); set_cairo_color(cr, 0); cairo_rectangle(cr, MAX(2,q->win_w-q->text_w-10), MAX(2,q->win_h-q->text_h-10), q->text_w+5, q->text_h+5); cairo_fill (cr); set_cairo_color(cr, STATUSBAR_BG); cairo_rectangle(cr, MAX(3,q->win_w-q->text_w-9), MAX(3,q->win_h-q->text_h-9), q->text_w+3, q->text_h+3); cairo_fill (cr); set_cairo_color(cr, 0); cairo_move_to (cr, MAX(5,q->win_w-q->text_w-7), MAX(5,q->win_h-7-q->text_h)); pango_cairo_show_layout(cr, layout); cairo_destroy (cr); } if(comment && comment_window) { /* draw comment */ cr = gdk_cairo_create (q->win); set_cairo_color(cr, 0); cairo_rectangle(cr, 25, MAX(5,q->win_h-q->comment_h-29), q->comment_w+5, q->comment_h+5); cairo_fill (cr); set_cairo_color(cr, COMMENT_BG); cairo_rectangle(cr, 26, MAX(6,q->win_h-q->comment_h-28), q->comment_w+3, q->comment_h+3); cairo_fill (cr); set_cairo_color(cr, 0); cairo_move_to (cr, 27, MAX(5,q->win_h - 26 - q->comment_h)); pango_cairo_show_layout(cr, layoutComment); cairo_destroy (cr); } if(artist && artist_window && strcmp(artist, artist_ignore)) { /* draw artist name in top left corner */ cr = gdk_cairo_create (q->win); set_cairo_color(cr, 0); cairo_rectangle(cr, 15, 15, q->artist_w+5, q->artist_h+5); cairo_fill (cr); set_cairo_color(cr, ARTIST_BG); cairo_rectangle(cr, 16, 16, q->artist_w+3, q->artist_h+3); cairo_fill (cr); set_cairo_color(cr, 0); cairo_move_to (cr, 17, 17); pango_cairo_show_layout(cr, layoutArtist); cairo_destroy (cr); } } // if (!fullscreen) else { # define statusbar_x monitor[q->mon_id].width # define statusbar_y monitor[q->mon_id].height if (mode == FULL_REDRAW) { #if GDK_MAJOR_VERSION < 3 gdk_window_clear(q->win); #else cr = gdk_cairo_create (q->win); set_cairo_color(cr, 0); cairo_rectangle(cr, 0, 0, monitor[q->mon_id].width, monitor[q->mon_id].height); cairo_fill (cr); cairo_destroy (cr); #endif } else { cr = gdk_cairo_create (q->win); set_cairo_color(cr, 0); if (q->win_x > q->win_ox) { cairo_rectangle(cr, q->win_ox, q->win_oy, q->win_x - q->win_ox, q->win_oh); cairo_fill (cr); } if (q->win_y > q->win_oy) { cairo_rectangle(cr, q->win_ox, q->win_oy, q->win_ow, q->win_y - q->win_oy); cairo_fill (cr); } if (q->win_x + q->win_w < q->win_ox + q->win_ow) { cairo_rectangle(cr, q->win_x + q->win_w, q->win_oy, q->win_ox + q->win_ow, q->win_oh); cairo_fill(cr); } if (q->win_y + q->win_h < q->win_oy + q->win_oh) { cairo_rectangle(cr, q->win_ox, q->win_y + q->win_h, q->win_ow, q->win_oy + q->win_oh); cairo_fill(cr); } if (q->statusbar_was_on && (!statusbar_fullscreen || q->text_ow > q->text_w || q->text_oh > q->text_h)) { cairo_rectangle(cr, statusbar_x-q->text_ow-9, statusbar_y-q->text_oh-9, q->text_ow+4, q->text_oh+4); cairo_fill(cr); } cairo_destroy(cr); } if (!q->error){ cr = gdk_cairo_create (q->win); GdkPixbuf* pb_tmp; if (gdk_pixbuf_get_n_channels(q->pb) == 3){ pb_tmp = gdk_pixbuf_scale_simple(q->pb, q->win_w, q->win_h, GDK_INTERP_BILINEAR); } else { GdkPixbuf* pb_tmp2; pb_tmp2 = gdk_pixbuf_scale_simple(q->pb, q->win_w, q->win_h, GDK_INTERP_BILINEAR); #if GDK_MAJOR_VERSION < 3 gdk_pixbuf_render_pixmap_and_mask_for_colormap (pb_tmp2, gdk_window_get_colormap(q->win), NULL, &mask, 128); #endif pb_tmp = gdk_pixbuf_composite_color_simple(pb_tmp2, q->win_w, q->win_h, GDK_INTERP_BILINEAR, 255, 0x08, 0x00666666, 0x00aaaaaa); g_object_unref(pb_tmp2); } gdk_cairo_set_source_pixbuf (cr, pb_tmp, q->win_x, q->win_y); g_object_unref(pb_tmp); /* remove or set transparency mask */ if (used_masks_before) { if (transparency) { #if GDK_MAJOR_VERSION < 3 gdk_window_shape_combine_mask(q->win, mask, q->win_x, q->win_y); #endif } else { #if GDK_MAJOR_VERSION < 3 gdk_window_shape_combine_mask(q->win, 0, q->win_x, q->win_y); #endif used_masks_before = 0; } } else { if (transparency && (gdk_pixbuf_get_n_channels(q->pb) == 4)) { #if GDK_MAJOR_VERSION < 3 gdk_window_shape_combine_mask(q->win, mask, q->win_x, q->win_y); #endif used_masks_before=1; } } cairo_rectangle(cr, 0, 0, q->win_w, q->win_h); cairo_paint(cr); cairo_destroy (cr); } if (statusbar_fullscreen) { cr = gdk_cairo_create (q->win); set_cairo_color(cr, 0); cairo_rectangle(cr, statusbar_x-q->text_w-10, statusbar_y-q->text_h-10, q->text_w+5, q->text_h+5); cairo_fill(cr); set_cairo_color(cr, STATUSBAR_BG); cairo_rectangle(cr,statusbar_x-q->text_w-9, statusbar_y-q->text_h-9, q->text_w+3, q->text_h+3); cairo_fill(cr); set_cairo_color(cr, 0); cairo_move_to(cr, statusbar_x-q->text_w-7, statusbar_y-7-q->text_h); pango_cairo_show_layout(cr, layout); cairo_destroy (cr); } if(comment && comment_window) { /* draw comment */ cr = gdk_cairo_create (q->win); set_cairo_color(cr, 0); cairo_rectangle(cr, 25, statusbar_y - q->comment_h - 30, q->comment_w + 5, q->comment_h + 5); cairo_fill(cr); set_cairo_color(cr, COMMENT_BG); cairo_rectangle(cr, 26, statusbar_y - q->comment_h - 29, q->comment_w + 3, q->comment_h + 3); cairo_fill(cr); set_cairo_color(cr, 0); cairo_move_to (cr, 27, statusbar_y - 27 - q->comment_h); pango_cairo_show_layout(cr, layoutComment); cairo_destroy (cr); } if(artist && artist_window && strcmp(artist, artist_ignore)) { /* draw artist name in top left corner*/ cr = gdk_cairo_create (q->win); set_cairo_color(cr, 0); cairo_rectangle(cr, 15, 15, q->artist_w + 5, q->artist_h + 5); cairo_fill(cr); set_cairo_color(cr, ARTIST_BG); cairo_rectangle(cr, 16, 16, q->artist_w + 3, q->artist_h + 3); cairo_fill(cr); set_cairo_color(cr, 0); cairo_move_to (cr, 17, 17); pango_cairo_show_layout(cr, layoutArtist); cairo_destroy (cr); } q->win_ox = q->win_x; q->win_oy = q->win_y; q->win_ow = q->win_w; q->win_oh = q->win_h; q->text_ow = q->text_w; q->text_oh = q->text_h; q->statusbar_was_on = statusbar_fullscreen; if(first) { gdk_window_show(q->win); first = 0; } gdk_window_move_resize(q->win, monitor[q->mon_id].x, monitor[q->mon_id].y, monitor[q->mon_id].width, monitor[q->mon_id].height); } gdk_display_flush(gdk_display_get_default()); #if GDK_MAJOR_VERSION < 3 if(mask) g_object_unref(mask); #endif } void reset_mod(qiv_image *q) { q->mod.brightness = default_brightness; q->mod.contrast = default_contrast; q->mod.gamma = default_gamma; } void destroy_image(qiv_image *q) { //printf("destroy image\n"); if (q->win) g_object_unref(q->win); q->win= NULL; if(!first) { if (q->pb) g_object_unref(q->pb); q->pb = NULL; } } void setup_magnify(qiv_image *q, qiv_mgl *m) { GdkWindowAttr mgl_attr; GdkGeometry mgl_hints; m->win_w=300; m->win_h=200; m->zoom=2.0; // gdk_flush(); gdk_window_get_root_origin(q->win, &m->frame_x, &m->frame_y); // printf("frame %d %d\n", m->frame_x, m->frame_y); mgl_attr.window_type=GDK_WINDOW_TOPLEVEL; // Set up attributes for GDK to create a Window mgl_attr.wclass=GDK_INPUT_OUTPUT; mgl_attr.event_mask=GDK_STRUCTURE_MASK | GDK_EXPOSURE_MASK; mgl_attr.width=m->win_w; mgl_attr.height=m->win_h; mgl_attr.override_redirect=TRUE; // m->win=gdk_window_new(NULL,&mgl_attr,GDK_WA_X|GDK_WA_Y|GDK_WA_WMCLASS); m->win=gdk_window_new(NULL,&mgl_attr,GDK_WA_X|GDK_WA_Y); mgl_hints.min_width=m->win_w; mgl_hints.max_width=m->win_w; mgl_hints.min_height=m->win_h; mgl_hints.max_height=m->win_h; gdk_window_set_geometry_hints(m->win, &mgl_hints, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); gdk_window_set_decorations(m->win, GDK_DECOR_BORDER); gdk_display_flush(gdk_display_get_default()); } void update_magnify(qiv_image *q, qiv_mgl *m, int mode, gint xcur, gint ycur) { // GdkWindowAttr mgl_attr; // GdkGeometry mgl_hints; register gint xx, yy; // win_pos_x, win_pos_y; cairo_t *cr; /*********** if (mode == FULL_REDRAW) { // printf("> update_magnify: FULL_REDRAW \n"); m->im=gdk_imlib_crop_and_clone_image( q->im, 0, 0, m->win_w, m->win_h); gdk_imlib_apply_image(m->im,m->win); mgl_hints.min_width=m->win_w; mgl_hints.max_width=m->win_w; mgl_hints.min_height=m->win_h; mgl_hints.max_height=m->win_h; // gdk_window_set_hints(m->win, mgl_attr.x, mgl_attr.y,mglw, // mglw,mglh, mglh, GDK_HINT_POS | GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); gdk_window_set_hints(m->win, xcur+50, ycur-50-m->win_h,m->win_w, m->win_w,m->win_h, m->win_h, GDK_HINT_POS | GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); // gdk_window_move_resize(m->win,mgl_attr.x, mgl_attr.y, mglw, mglh); // gdk_window_set_geometry_hints(magnify_img.win, &mgl_hints, GDK_HINT_POS ); } ************/ if (mode == REDRAW ) { /* scale position to original size */ xx=xcur * ((double)q->orig_w/(double)q->win_w); yy=ycur * ((double)q->orig_h/(double)q->win_h); /* center mouse cursor position */ xx -= 150 / m->zoom; yy -= 100 / m->zoom; /* keep magnify part allways inside image */ if(xx + m->win_w / m->zoom > q->orig_w) { xx=q->orig_w - m->win_w / m->zoom; } if(yy + m->win_h / m->zoom > q->orig_h) { yy=q->orig_h - m->win_h / m->zoom; } if (yy < 0){ yy=0; } if (xx < 0){ xx=0; } cr = gdk_cairo_create(m->win); cairo_scale(cr, m->zoom, m->zoom); gdk_cairo_set_source_pixbuf(cr, q->pb, -xx, -yy); cairo_paint(cr); cairo_destroy(cr); gdk_window_show(m->win); xx= m->frame_x + xcur - 50 - m->win_w; yy= m->frame_y + ycur - 50 - m->win_h; if (xx < 0) { if (xcur < m->win_w - magnify_img.frame_x) xx=m->frame_x + xcur + 50; else xx=0; } if (yy < 0) { if (ycur < m->win_h - magnify_img.frame_y) yy=m->frame_y + ycur + 50; else yy=0; } // printf("MGL: m->frame_x: %d, m->frame_y: %d, xx: %d, yy: %d\n", m->frame_x, m->frame_y, xx, yy); gdk_window_move(m->win, xx, yy); } gdk_display_flush(gdk_display_get_default()); } void center_image(qiv_image *q) { q->win_x = (monitor[q->mon_id].width - q->win_w) / 2; q->win_y = (monitor[q->mon_id].height - q->win_h) / 2; if(!fullscreen) { q->win_x += monitor[q->mon_id].x; q->win_y += monitor[q->mon_id].y; } } void correct_image_position(qiv_image *q) { // g_print("before: q->win_x = %d, q->win_y = %d, q->win_w = %d\n", q->win_x, q->win_y, q->win_w); /* try to keep inside the screen */ if (q->win_w < screen_x) { if (q->win_x < 0) q->win_x = 0; if (q->win_x + q->win_w > screen_x) q->win_x = screen_x - q->win_w; } else { if (q->win_x > 0) q->win_x = 0; if (q->win_x + q->win_w < screen_x) q->win_x = screen_x - q->win_w; } /* don't leave ugly borders */ if (q->win_h < screen_y) { if (q->win_y < 0) q->win_y = 0; if (q->win_y + q->win_h > screen_y) q->win_y = screen_y - q->win_h; } else { if (q->win_y > 0) q->win_y = 0; if (q->win_y + q->win_h < screen_y) q->win_y = screen_y - q->win_h; } // g_print("after: q->win_x = %d, q->win_y = %d, q->win_w = %d\n", q->win_x, q->win_y, q->win_w); } qiv-3.0.1/README.INSTALL0000664000175000001440000000077714774332451013200 0ustar andyusersPlease read the "README" file first! If you are using Debian/GNU Linux (or a derivative thereof) just type: dpkg-buildpackage -uc -B -m"your@email.address" -rfakeroot Otherwise type: "make install" (or "gmake install", if your standard make doesn't like the Makefile) to compile and install qiv. If you are compiling on FreeBSD, Solaris, or any other system without GNU getopt_long, comment out the GETOPT_LONG line in the Makefile. There are also a few other options there that can be set at compile time. qiv-3.0.1/README.TODO0000664000175000001440000000516614774332451012634 0ustar andyusersAs of end of March 2025, finally a GDK3 version of qiv is available. By changing a flag in the Makefile qiv can still be built with GDK2. It drops the dependency on imlib2 and breaks some imlib2 related features, most of them will hopefully brought back soon. Currently not working: * Color, brightness, gamma adjustment. * transparency (still works on GDK2) * setting root window (still works partly on GDK2, but never worked with "modern" desktop environment) A lot of deprecation warnings need to be cleaned up. ================================================= old TODO, good chance nothing of this will happen ================================================= - magnifying glass: [lc] + if the image is smaller than the magnifying window then it is stretched - would (black) borders be better? + doesn't work in fullscreen mode + the key sequence 'Mqypdx\egcC//cB8Bcccccccccccccccccccccccccccccccccccccccccccccccccc<"S !1AQSa"2eq45Us#3BR$brCcDt%&6d0Q!12aq3AR"#B ?:9e3{qo(y]iusRMӋq\ *MM)pE3뻭8"֯"ٓOڈfOVQgwZpE3뻭^DɧC2zP>ӂ(y]j&M?jՔx"֜CW2iP̞<ϮgwZOچde}wuP> Oچde.}wuP>L~3'K(y]i<Ϯu& RgwZpE3뻭]DɧC2z"֜CWQ2iP̞.}wuP>L~3'K(y]i<Ϯu& RgwZpE3뻭]DɧC2zP>ӂ(y]j&M?jԥ<ϮgwZOچd)pE3뻭8"֮d=YK(y]i<Ϯu& RgwZpE3뻭]DɧC2zP>ӂ(y]j&M?jՔ"֜CWQ2iP̞<ϮgwZOچde.}wuP>L~3'K(y]i<Ϯu& RgwZpE3뻭]DɧC2zʪ.JEK6@P;e1RC ,kDf1`lԹ2iP̞pE3뻭a t-{is<=6 Zyo krj%t쳶mYa첈;$@Y@A.4fOV\f@5Yr<ϮM cq9ȱlH< npuTG-mML%縉18k3e;Й4fOVdA` 9k {?;ފIm2- \?{UG.*DZWSD[HD@DDD@DDBQAӕ)qG *(D(@J(O:QG< Et%y΀QD((O:QG< Et@J" """ """{Z/p. [^] ҕB蕟=Ex~{ʼE^Wt|*si" """ cvlֲ1\Ǝyv#ޫ#{@*l7"Ԧ]sJƎE q::W{U{Ϳf<ekkOܞQusnL >R0^\6Wl܇T'3U['he`kI`TL<9t6SM7I?(ICz۾նB).Sw8\k]5ݞ].=LV*+DDD@DDBB蕟=Ex~{ʼE^Wt|*si" ""*8*]m!hVdZX\p\؊v߯N nxA^I$e%PJogryԯB-l6VQͼFcةt,7iW*V5^_ Do?$N)g-,Umѻ&d=cznN2FDoi:*Xr7a$e8qR0jwdĤ8xj푠2*Zs:Zo\{u9DEDDD@DDyT2xJ|>H3V%5#QU8TN:g+C+<*Cĺ×cNl !&fֽnw.Ty36қ+ks |{6ɿNH3CMLjttEohSNХsóҏ mWɮ`ȲPZ\0wJ}R=;g*=_unUt\ AڷAUͶϽh r~kvڡd2^]5D.Up T.cyL?Al_:ceڒVuzv ӿTa7Kl#}}?uwAy? Kľ&F35xnٗ1 nV-Gw>m[6-}3W?N ^UIb;qSX)7[zݽks`9VHA*0 /@]Z@]{a_EY2wd"" """ @r=Dhz/?>f[Ǖ \?{UG.*DZWSD[HD@DDD@B'Wa@k&?*Ӱn"O+_*A=va3(= UŚ'nMA=-24!fm)HM/,V]Q3qh aȱYUS6aۜ ,˸QY+5n /ƮGr6˟[2:猗UsR3ޅ| TgŸ}NC?^5y<Ӽb߱!B z^C+XSC*KWpFAW>U Gx6apH߿Rnծ>v޹1ْoJ!x^7y#r.'K<œ0E<$nUy|d0à]jnG,D\QmYO"0I @xrݤD?ֱq7 /ɈVEu`;TH[{ή QDDD@DD T 9 ϞV|w3-ʎ.*y]ث"-" """ ˼(;cZ x[_Ue&/ѽpc!g:(J$fáVYnR%7\q,> 1w|8nR]ĺ(pkpGڃof-1d~PMiWC~WI-XVC~m oeXnNjȼ$*[=7hf4 qhŹ|V ;Jl r=VkmQ5S6^ڇS{qU˷K c$ Ej!jهGs_"l0x}'y=x,~] 5=νJ؞%I`/K7c`OJ0(;U%PNKq8_^Rw-WМgKkuHN%|Mi9˱9\lT@=ӱm\a!hE+q7 HsYwD@DDD@PBhz%ggG{y2<_*8/pyW.=""@""" ""J <: }뭦4ڎ Qne;{o^~UFPۗR}BMђgmB *zoƵ\ˉkYF.b*vRfN ,K ڹȫA{V.f4e%w]u y6s {[*I7U+I% R$'7,<ɶ!4.P\g;T˰!B tHE?=G޵ԟHE?;Gޮp|v'7&_̕:m뢰֤Ճ0 򮪱ڷNV;/G^W{pE#/ků1'[qT7%7- ڌ4T;2FgH1h8ji5eJ+i""" """ @r=Dhz/?>f[Ǖ \?{UG.*DZWSD[HD@DDD@ ]E J9{@䴎E~7\I n5mWZ&ݺ;*[O7Wviu:m|9YY+JU%y&:ǓRz R_PT-e[BlJÚ3jO GSݵqF?ʓXc<1:F[QӺ4ըc*V5:fH:l*Lֽ$2F, JkwgDY0DDD@DD T 9 ϞV|w3-ʎ.*y]ث"-" """ "(@9C{ Sld'we"M#XæbtQZ0U ;65I؋ENNdڊoпTksJZزklb:cw[b4o{ڈ0MƼf6+KC^c9_gst+49 ɷdn#FiQcb}^ۊmGS6gi:_Ul9mR4M3(xbH6q'@ś = ܩTL!p{}auTwܱLB9+ps LDDD@DDD@)P+>{?;މY^~|̷*:,~ʎ \?{UwGˏb;""" ""U/&3g4K]]X㫦|2MŤf-&q죧f+*++ZnYg1L&w-/G}kEvpف~UvT܏:\MD[we73Z(ޮ}}TV9R*#[BNjK^EU㪐XӐ5=\:p\eC; =f;+ $kȶx {J9bmm$l䎔$aTj):]@ƜG$撒i\.|#{WMS>`0 0<'iE؋2iʲK{l}v"݌2#NoV䣨avEkCSԺѼ:mcublU$S5PɨOЖdmdQC&gF;t s[5G i]{?;ދϙGEyQ~{ʼqUaD@DDBQB %"QB %"QB %"QB %"QB %"QB %"QB %B"Q u(ԢJ """ ""J!YJϞeyQ`E^\ 4/ݔ=|Q? DZWS@E(;~_?iSo=@}~iP@E(;~|o=N( iSo=@w(;~~iSo=@w(;~~iSo=@w(;~~iSo=@w(;~~iSo=@w(;~~iSo=@w(;~~iSo=@w(;~~iSo=@}~iP@E(;~|o=N(_?iSo=@}~iP@E(;~|o=N(_?iSo=@}~iP@E(;~.o=N(hz* 6i}m:/?>f[ǕWdM}B-7UXSSD|p=T8 ԯ(q슺עp1Uw8 Զ5}U]N>w 5}U]N>w 5}U]N>w 5}U]N>w 5}U]N>w 5Z5`XUގ,cGRWVS) :zs\m]p6 DnGG\tcyidzPj./vIK $MwvOMMfRrΊGQn @!$`<&ýeë_M؍2pFMiJ<[ 4N a{e;Zcoz5;.s}YA\ j%JE F; e驢.,|m.:ցNY&Jx0Ka,vFPHD +YWЀ͆?G}DiNf İq*`\4z2cA 67 jy%&pD^(D]mj) 2BG,ns.Zit*| _6qdl,)'_FI!͑'Yysx>jK6+\w vmV잪HʘoQsa@X|8Q6 %MA~Uh0K4[ ^@G^ijK kԕ gc%N]bU?%+浈dlcTPGvD.ZG%eb))DO(k <}OAZ19! erj&&Rڦ*0m '2R<b[Yj"!Sf1{jAЋATC;$l2ZR\gh%}$Ҳ9$eDp7 jO*'axtoeCR#LK ħ{@qcЪaX,SU;53ztGa5/qq xeH z-cUWz;H z-cUWz;H z-cUWz;H z-cUWz;H z-cUWz;H z-cUWz;H z-cUWz;H z-cUWz;H6YPP#\Dz&p Ao_*8/pyW.=""@""" """ UEe~Fl*[C3X$-Ѥ oaY+iJ=ťۮVD@DDg^'e}F2΀"""tԺv6 9Z,m,,1Ǻ7exkZy"2*T>NcnS]o gc.1,ommcD@DDD@E969XF uO!YD@Bafط>7}/ƀ̡J!YJϞeyQ`E^Tp_+>\{u9DEDDD@DDD@i&Y o¦'ƗM z x㶙v\ᵭaD!X!Zicp[w8؝ z5JqIOI[ONichٜH{[k䤩GKET븗:{;4G1Ҍ_tTu2H/p`ONlBcL$7H#Ę ln nsvHo`iP 㕵G+d G83ZCr9W[faͩ{0x| ""fj[nsmِ]qm8aTTs؊A#@cIٍtAn[;f%=de\׳y7vRt,2cMEG]C)H>PHc] vAm6.˻/p@Ǚ9l&G- K SO,6I<5.g\[UZZ죬{ʨaZq2'KDCY5lˈTY;f {mq-fYQME'GDŽG {7vZڞէ/kv;+hɻ~.NOճ'=U;T32GH`#] ĩ&Sls4JGH[mso{@r=Dhz/?>f[Ǖ1 =jBh;+_w/]6sX$nkpEUC, !~̴M[+>\{u9] Qel82Ӗa9UJx祖dZ m]4r$rR@HwzTOJttLhۀt[H#ts>60$y[yH;A&6-cNSM%em6/Slq:f=.?ü:V ݒcQV"ۛv޶KDv`9|ۥz6 6gH3J:" 1%ƽs\.TE Է8t?]w ] "[°#_һN?ݓq6uJ:Zi}Sv0e\\ZlDqG{ `?3'-8C$n֦)d:1:F]b)bE@ʗg}< ٌaVJH:Gz76Au.-ffգЀ$Q2Ag hCZm9tAs"iYOES,MZ Ii`( [mK^d/Fd~fݖbIVqBw n97y9b1lEVSGD^-i. $F gM+9^cKccvAN0̧eI©ƲK5pޗ_Rl|zZ%'m0nSyBĩ)btSE2Qvh iaEPIHa[K\kmk0tSFؚHH(q^:ƶH əٯsk\i] DL'Z{Cu=+jܝW2mI<=ټ*[ ss|C=BkXFhԐ$ ֞ 6tb_+!x4[Lۭb*édIK l;Yy^caMS#1gdw.:9ajha--vnUk*J\̥"/ӿT8BeI4|yl" !+6!WE_=\Uf6KjՁğ17eaBX;r&\>lZ:wf͹_'BikvywVjH ۅ7 k7Tv̎hm ˛Qc-;X;um L*cMF&k 9E4FH̏GEwݦC{^KsSP7E l{.-}tUp 9hi/3-gy7=ӓDTtEJꗖ ffo\|̣ˑl8]tUG9:呡*-+i /2hbcd80:FۓCC>?Lɪ1AES|y&N'8;,5[Mngm}{zIM!O;y(^fWI5$= s$n6p1c cNe ۻ\ ZZn3\q훝Fe`sI}um=<\r\"UvФQ@j;a5SUe<.4K%]EN ثMKZ>5~趱SF%1&@_H9iddsԘ!M |Oh(d@^.t h+Xh9îۃ`m!nxj;\cf]444qo*t4`K0 I$r4@s~1֦X'WcfZ@o|*FjUJC(b#`u,{yukZMkc1,mvݠ;FBXcŲ jt@s;YO3aO$,s }I7rT}tO:&i_0V䑑F${X 6 tl}DP1tpE#.;+M_j{)~Fm~ T 9 ϞV|w3-ʎ.*y]ث"-$l7#{?;މY^~|̷*:,~ʎ \?{UwGˏb;(R^*wOP@$4ܐBIJvGIx?XuI ll/6ߧqq.I+JmO-WSUs~Rb6L:JnaX`X%K#,eX [rU\c,u_(0ZC ?+ cɌlF޶L͐gh#P O8sG$E^7T&tϧN죙rxmhpMZg Ibl ͶmN؇Sm@%ݛ]mm۸ʼn$cʊO3]f)di.gyMwUs~b5fsi ?^Gz4#ia][=6Fd8ۚnUb*m1NUs~Aߥi(]QSSO,B9isevf`2q$E|j}oҟ(0ZC:xcce}C=E`]NĸXNJwc?+ϸ1z|U'e삧 Nz$>Pa^7Z{47#-1rU$ݸt7XY g`9eױb8d4)OfsCy5aelUI qwlt:ieg{)Y+g#02 ]YזUs~AzߥrcRF6HECGQUWS5>TvQ15׸7:@4!Sj;FNUs~AzߥqXUC*naq \+)ͷ9Mkb'Z;O-WU.™Pg}m3e [,ΗutU,3:XLmS}l}&7U-=D64 .^$j ?)9Jq2Idz.qs܋$EPdnYط_%Z:-WSUs~c5' Jv.˂@6[ZZHNW:\h^I방ft>悖Pq i 1a ED>^72f<]+@]s4F۸¡KVT2{[5s'{V/刓"DPa>7O-WWTڇ=E0meHdθhB`I,r:j͛ nHYt#I7c}Q9K`A!Lj(0ZCs{&GIV;#IiƋ.f~w>ڎ2up7c!sQˢIJpU~bRIm}wc}OJN7b2:Ca:w͘cTo](Aߥ>PPrߥs%^),s#p9MvrߏEXto1Ӂ&Y]0^7ⰱ%?ʎW9JpUs~s:\FڗNru ܮbaˋqtFxFn&U{ϔ-WPAAS~OYfsmw5;N k'!mmCLd|wO)L1u?(0ZC ?+kY4ӹ@ȟ!/i㰷^[]rv3vߋ]+ˆJc hxsKMߩ+/ ?+Ƕv˜G ^]D dXnl㒈J؛!pU7(FT_u?(0ZC ?+MH -N#cFH!-.Ymk4M޵9j12>'I9JESWFSB. rqXi1:c#$mͬvRΟ.Z!UyM٭mggG{+>{?;ފ|̱*:,~!R`2,-]VisIɻJ.[UIޥ?  =QԢZ[Ԝ-]O Jw?귩8Z[Ԟ:1g6Tae~D *n , 3ǘt$r-]8ZGReɌTς 09cgyIV[ k&h=u煫Tu)joRBJ?ߓ*U?mvmfnZ[ACPHx{ |-]Sޥ=~u:[9-8%KkYg֛&[Vh(jaAFFw4ԓaʲpw?귩8Z[ԲQ:CU U[ٰ<=6IU gkO,#q]~V)joR©B6!Ө1CUKW4=h9EEݲ׽yk_rޤjoRfQ~F]N(U:EY-.t/{k&ɹ{t=KvbⓡzjoRpw?귩aʃi~g. 0dn TLFn9r ç S - -]Sޥ/_]N 2z.X\٣i-