From 0f65f32062e794bbc102036722db571bc96ddfd2 Mon Sep 17 00:00:00 2001 From: "raveit65 (via Travis CI)" Date: Tue, 4 Aug 2020 11:01:33 +0000 Subject: Deploy mate-desktop/eom to github.com/mate-desktop/eom.git:gh-pages --- .../0.html | 3908 +++++++ .../1.html | 1484 +++ .../10.html | 5122 ++++++++ .../11.html | 2080 ++++ .../12.html | 2056 ++++ .../13.html | 1534 +++ .../14.html | 414 + .../15.html | 2274 ++++ .../16.html | 1910 +++ .../17.html | 2806 +++++ .../18.html | 760 ++ .../19.html | 4894 ++++++++ .../2.html | 2136 ++++ .../20.html | 2352 ++++ .../21.html | 2148 ++++ .../22.html | 1158 ++ .../23.html | 11714 +++++++++++++++++++ .../3.html | 2246 ++++ .../4.html | 584 + .../5.html | 1544 +++ .../6.html | 598 + .../7.html | 890 ++ .../8.html | 1272 ++ .../9.html | 1226 ++ .../index.html | 247 + .../stats.html | 108 + .../style.css | 149 + 27 files changed, 57614 insertions(+) create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/0.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/1.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/10.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/11.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/12.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/13.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/14.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/15.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/16.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/17.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/18.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/19.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/2.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/20.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/21.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/22.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/23.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/3.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/4.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/5.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/6.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/7.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/8.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/9.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/index.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/stats.html create mode 100644 2020-07-13-084614-7902-cppcheck@c331ec988f54_master/style.css (limited to '2020-07-13-084614-7902-cppcheck@c331ec988f54_master') diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/0.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/0.html new file mode 100644 index 0000000..5eb26ac --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/0.html @@ -0,0 +1,3908 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
/*
+ *  Copyright (C) 2003, 2004  Marco Pesenti Gritti
+ *  Copyright (C) 2003, 2004, 2005  Christian Persch
+ *
+ *  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, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *  $Id: egg-editable-toolbar.c 937 2009-04-07 11:16:53Z friemann $
+ */
+
+#include "config.h"
+
+#include "egg-editable-toolbar.h"
+#include "egg-toolbars-model.h"
+#include "egg-toolbar-editor.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+static GdkPixbuf * new_separator_pixbuf         (void);
+
+#define MIN_TOOLBAR_HEIGHT 20
+#define EGG_ITEM_NAME      "egg-item-name"
+#define STOCK_DRAG_MODE    "stock_drag-mode"
+
+static const GtkTargetEntry dest_drag_types[] = {
+  {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
+};
+
+enum
+{
+  PROP_0,
+  PROP_TOOLBARS_MODEL,
+  PROP_UI_MANAGER,
+  PROP_POPUP_PATH,
+  PROP_SELECTED,
+  PROP_EDIT_MODE
+};
+
+enum
+{
+  ACTION_REQUEST,
+  LAST_SIGNAL
+};
+
+static guint egg_editable_toolbar_signals[LAST_SIGNAL] = { 0 };
+
+struct _EggEditableToolbarPrivate
+{
+  GtkUIManager *manager;
+  EggToolbarsModel *model;
+  guint edit_mode;
+  gboolean save_hidden;
+  GtkWidget *fixed_toolbar;
+
+  GtkWidget *selected;
+  GtkActionGroup *actions;
+
+  guint visibility_id;
+  GList *visibility_paths;
+  GPtrArray *visibility_actions;
+
+  char *popup_path;
+
+  guint        dnd_pending;
+  GtkToolbar  *dnd_toolbar;
+  GtkToolItem *dnd_toolitem;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (EggEditableToolbar, egg_editable_toolbar, GTK_TYPE_BOX)
+
+static int
+get_dock_position (EggEditableToolbar *etoolbar,
+                   GtkWidget *dock)
+{
+  GList *l;
+  int result;
+
+  l = gtk_container_get_children (GTK_CONTAINER (etoolbar));
+  result = g_list_index (l, dock);
+  g_list_free (l);
+
+  return result;
+}
+
+static int
+get_toolbar_position (EggEditableToolbar *etoolbar, GtkWidget *toolbar)
+{
+  return get_dock_position (etoolbar, gtk_widget_get_parent (toolbar));
+}
+
+static int
+get_n_toolbars (EggEditableToolbar *etoolbar)
+{
+  GList *l;
+  int result;
+
+  l = gtk_container_get_children (GTK_CONTAINER (etoolbar));
+  result = g_list_length (l);
+  g_list_free (l);
+
+  return result;
+}
+
+static GtkWidget *
+get_dock_nth (EggEditableToolbar *etoolbar,
+	      int                 position)
+{
+  GList *l;
+  GtkWidget *result;
+
+  l = gtk_container_get_children (GTK_CONTAINER (etoolbar));
+  result = g_list_nth_data (l, position);
+  g_list_free (l);
+
+  return result;
+}
+
+static GtkWidget *
+get_toolbar_nth (EggEditableToolbar *etoolbar,
+		 int                 position)
+{
+  GList *l;
+  GtkWidget *dock;
+  GtkWidget *result;
+
+  dock = get_dock_nth (etoolbar, position);
+  g_return_val_if_fail (dock != NULL, NULL);
+
+  l = gtk_container_get_children (GTK_CONTAINER (dock));
+  result = GTK_WIDGET (l->data);
+  g_list_free (l);
+
+  return result;
+}
+
+static GtkAction *
+find_action (EggEditableToolbar *etoolbar,
+	     const char         *name)
+{
+  GList *l;
+  GtkAction *action = NULL;
+
+  l = gtk_ui_manager_get_action_groups (etoolbar->priv->manager);
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  for (; l != NULL; l = l->next)
+    {
+      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+      GtkAction *tmp;
+
+      tmp = gtk_action_group_get_action (GTK_ACTION_GROUP (l->data), name);
+      if (tmp)
+        action = tmp;
+      G_GNUC_END_IGNORE_DEPRECATIONS;
+    }
+
+  return action;
+}
+
+static void
+drag_data_delete_cb (GtkWidget          *widget,
+		     GdkDragContext     *context,
+		     EggEditableToolbar *etoolbar)
+{
+  int pos, toolbar_pos;
+
+  widget = gtk_widget_get_ancestor (widget, GTK_TYPE_TOOL_ITEM);
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (etoolbar));
+
+  pos = gtk_toolbar_get_item_index (GTK_TOOLBAR (gtk_widget_get_parent (widget)),
+				    GTK_TOOL_ITEM (widget));
+  toolbar_pos = get_toolbar_position (etoolbar, gtk_widget_get_parent (widget));
+
+  egg_toolbars_model_remove_item (etoolbar->priv->model,
+				  toolbar_pos, pos);
+}
+
+static void
+drag_begin_cb (GtkWidget          *widget,
+	       GdkDragContext     *context,
+	       EggEditableToolbar *etoolbar)
+{
+  GtkAction *action;
+  const gchar *action_name;
+  gint flags;
+
+  gtk_widget_hide (widget);
+
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+  action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (widget));
+
+  if (action == NULL) return;
+
+  action_name = gtk_action_get_name (action);
+  G_GNUC_END_IGNORE_DEPRECATIONS;
+
+  flags = egg_toolbars_model_get_name_flags (etoolbar->priv->model,
+                                             action_name);
+  if (!(flags & EGG_TB_MODEL_NAME_INFINITE))
+    {
+      flags &= ~EGG_TB_MODEL_NAME_USED;
+      egg_toolbars_model_set_name_flags (etoolbar->priv->model,
+                                         action_name,
+                                         flags);
+    }
+}
+
+static void
+drag_end_cb (GtkWidget          *widget,
+	     GdkDragContext     *context,
+	     EggEditableToolbar *etoolbar)
+{
+  GtkAction *action;
+  const gchar *action_name;
+  gint flags;
+
+  if (gtk_widget_get_parent (widget) != NULL)
+    {
+      gtk_widget_show (widget);
+
+      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+      action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (widget));
+
+      if (action == NULL) return;
+
+      action_name = gtk_action_get_name (action);
+      G_GNUC_END_IGNORE_DEPRECATIONS;
+
+      flags = egg_toolbars_model_get_name_flags (etoolbar->priv->model,
+                                                 action_name);
+      if (!(flags & EGG_TB_MODEL_NAME_INFINITE))
+        {
+          flags |= EGG_TB_MODEL_NAME_USED;
+          egg_toolbars_model_set_name_flags (etoolbar->priv->model,
+                                             action_name,
+                                             flags);
+        }
+    }
+}
+
+static void
+drag_data_get_cb (GtkWidget          *widget,
+		  GdkDragContext     *context,
+		  GtkSelectionData   *selection_data,
+		  guint               info,
+		  guint32             time,
+		  EggEditableToolbar *etoolbar)
+{
+  EggToolbarsModel *model;
+  const char *name;
+  char *data;
+
+  g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (etoolbar));
+  model = egg_editable_toolbar_get_model (etoolbar);
+
+  name = g_object_get_data (G_OBJECT (widget), EGG_ITEM_NAME);
+  if (name == NULL)
+    {
+      name = g_object_get_data (G_OBJECT (gtk_widget_get_parent (widget)), EGG_ITEM_NAME);
+      g_return_if_fail (name != NULL);
+    }
+
+  data = egg_toolbars_model_get_data (model, gtk_selection_data_get_target (selection_data), name);
+  if (data != NULL)
+    {
+      gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (unsigned char *)data, strlen (data));
+      g_free (data);
+    }
+}
+
+static void
+move_item_cb (GtkAction          *action,
+              EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolitem = gtk_widget_get_ancestor (egg_editable_toolbar_get_selected (etoolbar), GTK_TYPE_TOOL_ITEM);
+  GtkTargetList *list = gtk_target_list_new (dest_drag_types, G_N_ELEMENTS (dest_drag_types));
+
+  GdkEvent *realevent = gtk_get_current_event();
+  GdkEventMotion event;
+  event.type = GDK_MOTION_NOTIFY;
+  event.window = realevent->any.window;
+  event.send_event = FALSE;
+  event.axes = NULL;
+  event.time = gdk_event_get_time (realevent);
+  gdk_event_get_state (realevent, &event.state);
+  gdk_event_get_coords (realevent, &event.x, &event.y);
+  gdk_event_get_root_coords (realevent, &event.x_root, &event.y_root);
+
+  gtk_drag_begin_with_coordinates (toolitem,
+                                   list,
+                                   GDK_ACTION_MOVE,
+                                   1,
+                                   (GdkEvent *)&event,
+                                   event.x,
+                                   event.y);
+  gtk_target_list_unref (list);
+}
+
+static void
+remove_item_cb (GtkAction          *action,
+                EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolitem = gtk_widget_get_ancestor (egg_editable_toolbar_get_selected (etoolbar), GTK_TYPE_TOOL_ITEM);
+  int pos, toolbar_pos;
+
+  toolbar_pos = get_toolbar_position (etoolbar, gtk_widget_get_parent (toolitem));
+  pos = gtk_toolbar_get_item_index (GTK_TOOLBAR (gtk_widget_get_parent (toolitem)),
+				    GTK_TOOL_ITEM (toolitem));
+
+  egg_toolbars_model_remove_item (etoolbar->priv->model,
+			          toolbar_pos, pos);
+
+  if (egg_toolbars_model_n_items (etoolbar->priv->model, toolbar_pos) == 0)
+    {
+      egg_toolbars_model_remove_toolbar (etoolbar->priv->model, toolbar_pos);
+    }
+}
+
+static void
+remove_toolbar_cb (GtkAction          *action,
+		   EggEditableToolbar *etoolbar)
+{
+  GtkWidget *selected = egg_editable_toolbar_get_selected (etoolbar);
+  GtkWidget *toolbar = gtk_widget_get_ancestor (selected, GTK_TYPE_TOOLBAR);
+  int toolbar_pos;
+
+  toolbar_pos = get_toolbar_position (etoolbar, toolbar);
+  egg_toolbars_model_remove_toolbar (etoolbar->priv->model, toolbar_pos);
+}
+
+static void
+popup_context_deactivate (GtkMenuShell *menu,
+			  EggEditableToolbar *etoolbar)
+{
+  egg_editable_toolbar_set_selected (etoolbar, NULL);
+  g_object_notify (G_OBJECT (etoolbar), "selected");
+}
+
+static void
+popup_context_menu_cb (GtkWidget          *toolbar,
+                       gint		   x,
+                       gint		   y,
+                       gint                button_number,
+                       EggEditableToolbar *etoolbar)
+{
+  if (etoolbar->priv->popup_path != NULL)
+    {
+      GtkMenu *menu;
+
+      egg_editable_toolbar_set_selected (etoolbar, toolbar);
+      g_object_notify (G_OBJECT (etoolbar), "selected");
+
+      menu = GTK_MENU (gtk_ui_manager_get_widget (etoolbar->priv->manager,
+						  etoolbar->priv->popup_path));
+      g_return_if_fail (menu != NULL);
+      gtk_menu_popup_at_pointer (menu, NULL);
+      g_signal_connect_object (menu, "selection-done",
+			       G_CALLBACK (popup_context_deactivate),
+			       etoolbar, 0);
+    }
+}
+
+static gboolean
+button_press_event_cb (GtkWidget *widget,
+                       GdkEventButton *event,
+                       EggEditableToolbar *etoolbar)
+{
+  if (event->button == 3 && etoolbar->priv->popup_path != NULL)
+    {
+      GtkMenu *menu;
+
+      egg_editable_toolbar_set_selected (etoolbar, widget);
+      g_object_notify (G_OBJECT (etoolbar), "selected");
+
+      menu = GTK_MENU (gtk_ui_manager_get_widget (etoolbar->priv->manager,
+						  etoolbar->priv->popup_path));
+      g_return_val_if_fail (menu != NULL, FALSE);
+      gtk_menu_popup_at_pointer (menu, (const GdkEvent*) event);
+      g_signal_connect_object (menu, "selection-done",
+			       G_CALLBACK (popup_context_deactivate),
+			       etoolbar, 0);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+configure_item_sensitivity (GtkToolItem *item, EggEditableToolbar *etoolbar)
+{
+  GtkAction *action;
+  char *name;
+
+  name = g_object_get_data (G_OBJECT (item), EGG_ITEM_NAME);
+  action = name ? find_action (etoolbar, name) : NULL;
+
+  if (action)
+    {
+      g_object_notify (G_OBJECT (action), "sensitive");
+    }
+
+  gtk_tool_item_set_use_drag_window (item,
+				     (etoolbar->priv->edit_mode > 0) ||
+				     GTK_IS_SEPARATOR_TOOL_ITEM (item));
+
+}
+
+static void
+configure_item_cursor (GtkToolItem *item,
+		       EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  GtkWidget *widget = GTK_WIDGET (item);
+
+  if (gtk_widget_get_window (widget) != NULL)
+    {
+      if (priv->edit_mode > 0)
+        {
+          GdkCursor *cursor;
+	  GdkScreen *screen;<--- Shadowed declaration
+          GdkPixbuf *pixbuf = NULL;
+
+	  screen = gtk_widget_get_screen (GTK_WIDGET (etoolbar));
+
+          cursor = gdk_cursor_new_for_display (gdk_screen_get_display (screen),
+					       GDK_HAND2);
+          gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
+          g_object_unref (cursor);
+
+          gtk_drag_source_set (widget, GDK_BUTTON1_MASK, dest_drag_types,
+                               G_N_ELEMENTS (dest_drag_types), GDK_ACTION_MOVE);
+          if (GTK_IS_SEPARATOR_TOOL_ITEM (item))
+            {
+              pixbuf = new_separator_pixbuf ();
+            }
+          else
+            {
+              char *icon_name=NULL;
+              char *stock_id=NULL;
+              GtkAction *action;
+              char *name;
+
+              name = g_object_get_data (G_OBJECT (widget), EGG_ITEM_NAME);
+              action = name ? find_action (etoolbar, name) : NULL;
+
+              if (action)
+                {
+                   g_object_get (action,
+                                 "icon-name", &icon_name,
+                                 "stock-id", &stock_id,
+                                 NULL);
+                }
+              if (icon_name)
+                {
+                  GdkScreen *screen;<--- Shadow variable
+                  GtkIconTheme *icon_theme;
+                  gint width, height;
+
+                  screen = gtk_widget_get_screen (widget);
+                  icon_theme = gtk_icon_theme_get_for_screen (screen);
+
+                  if (!gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR,
+                                             &width, &height))
+                    {
+                      width = height = 24;
+                    }
+
+                  pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name,
+                                                     MIN (width, height), 0, NULL);
+                }
+              else if (stock_id)
+                {
+                  pixbuf = gtk_widget_render_icon (widget, stock_id,
+	                                           GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
+                }
+              g_free (icon_name);
+              g_free (stock_id);
+            }
+
+          if (G_UNLIKELY (!pixbuf))
+            {
+              return;
+            }
+          gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
+          g_object_unref (pixbuf);
+
+        }
+      else
+        {
+          gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(item)), NULL);
+        }
+    }
+}
+
+
+static void
+configure_item_tooltip (GtkToolItem *item)
+{
+  GtkAction *action;
+
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+  action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (item));
+  G_GNUC_END_IGNORE_DEPRECATIONS;
+
+  if (action != NULL)
+    {
+      g_object_notify (G_OBJECT (action), "tooltip");
+    }
+}
+
+
+static void
+connect_widget_signals (GtkWidget *proxy, EggEditableToolbar *etoolbar)
+{
+  if (GTK_IS_CONTAINER (proxy))
+    {
+       gtk_container_forall (GTK_CONTAINER (proxy),
+			     (GtkCallback) connect_widget_signals,
+			     (gpointer) etoolbar);
+    }
+
+  if (GTK_IS_TOOL_ITEM (proxy))
+    {
+      g_signal_connect_object (proxy, "drag_begin",
+			       G_CALLBACK (drag_begin_cb),
+			       etoolbar, 0);
+      g_signal_connect_object (proxy, "drag_end",
+			       G_CALLBACK (drag_end_cb),
+			       etoolbar, 0);
+      g_signal_connect_object (proxy, "drag_data_get",
+			       G_CALLBACK (drag_data_get_cb),
+			       etoolbar, 0);
+      g_signal_connect_object (proxy, "drag_data_delete",
+			       G_CALLBACK (drag_data_delete_cb),
+			       etoolbar, 0);
+    }
+
+  if (GTK_IS_BUTTON (proxy) || GTK_IS_TOOL_ITEM (proxy))
+    {
+      g_signal_connect_object (proxy, "button-press-event",
+			       G_CALLBACK (button_press_event_cb),
+			       etoolbar, 0);
+    }
+}
+
+static void
+action_sensitive_cb (GtkAction   *action,
+                     GParamSpec  *pspec,
+                     GtkToolItem *item)
+{
+  EggEditableToolbar *etoolbar;
+  GtkWidget *ancestor = gtk_widget_get_ancestor (GTK_WIDGET (item), EGG_TYPE_EDITABLE_TOOLBAR);
+
+  if (!ancestor)
+    return;
+
+  etoolbar = EGG_EDITABLE_TOOLBAR (ancestor);
+
+  if (etoolbar->priv->edit_mode > 0)
+    {
+      gtk_widget_set_sensitive (GTK_WIDGET (item), TRUE);
+    }
+}
+
+static GtkToolItem *
+create_item_from_action (EggEditableToolbar *etoolbar,
+			 const char *name)
+{
+  GtkToolItem *item;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  if (strcmp (name, "_separator") == 0)
+    {
+      item = gtk_separator_tool_item_new ();
+    }
+  else
+    {
+      GtkAction *action = find_action (etoolbar, name);
+      if (action == NULL) return NULL;
+
+      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+      item = GTK_TOOL_ITEM (gtk_action_create_tool_item (action));
+
+      /* Normally done on-demand by the GtkUIManager, but no
+       * such demand may have been made yet, so do it ourselves.
+       */
+      gtk_action_set_accel_group
+        (action, gtk_ui_manager_get_accel_group(etoolbar->priv->manager));
+      G_GNUC_END_IGNORE_DEPRECATIONS;
+
+      g_signal_connect_object (action, "notify::sensitive",
+                               G_CALLBACK (action_sensitive_cb), item, 0);
+    }
+
+  gtk_widget_show (GTK_WIDGET (item));
+
+  g_object_set_data_full (G_OBJECT (item), EGG_ITEM_NAME,
+                          g_strdup (name), g_free);
+
+  return item;
+}
+
+static GtkToolItem *
+create_item_from_position (EggEditableToolbar *etoolbar,
+                           int                 toolbar_position,
+                           int                 position)
+{
+  GtkToolItem *item;
+  const char *name;
+
+  name = egg_toolbars_model_item_nth (etoolbar->priv->model, toolbar_position, position);
+  item = create_item_from_action (etoolbar, name);
+
+  return item;
+}
+
+static void
+toolbar_drag_data_received_cb (GtkToolbar         *toolbar,
+                               GdkDragContext     *context,
+                               gint                x,
+                               gint                y,
+                               GtkSelectionData   *selection_data,
+                               guint               info,
+                               guint               time,
+                               EggEditableToolbar *etoolbar)
+{
+  /* This function can be called for two reasons
+   *
+   *  (1) drag_motion() needs an item to pass to
+   *      gtk_toolbar_set_drop_highlight_item(). We can
+   *      recognize this case by etoolbar->priv->pending being TRUE
+   *      We should just create an item and return.
+   *
+   *  (2) The drag has finished, and drag_drop() wants us to
+   *      actually add a new item to the toolbar.
+   */
+
+  GdkAtom type = gtk_selection_data_get_data_type (selection_data);
+  const char *data = (char *)gtk_selection_data_get_data (selection_data);
+
+  int ipos = -1;
+  char *name = NULL;
+  gboolean used = FALSE;
+
+  /* Find out where the drop is occurring, and the name of what is being dropped. */
+  if (gtk_selection_data_get_length (selection_data) >= 0)
+    {
+      ipos = gtk_toolbar_get_drop_index (toolbar, x, y);
+      name = egg_toolbars_model_get_name (etoolbar->priv->model, type, data, FALSE);
+      if (name != NULL)
+	{
+	  used = ((egg_toolbars_model_get_name_flags (etoolbar->priv->model, name) & EGG_TB_MODEL_NAME_USED) != 0);
+        }
+    }
+
+  /* If we just want a highlight item, then . */
+  if (etoolbar->priv->dnd_pending > 0)
+    {
+      etoolbar->priv->dnd_pending--;
+
+      if (name != NULL && etoolbar->priv->dnd_toolbar == toolbar && !used)
+        {
+          etoolbar->priv->dnd_toolitem = create_item_from_action (etoolbar, name);
+          gtk_toolbar_set_drop_highlight_item (etoolbar->priv->dnd_toolbar,
+                                               etoolbar->priv->dnd_toolitem, ipos);
+        }
+    }
+  else
+    {
+      gtk_toolbar_set_drop_highlight_item (toolbar, NULL, 0);
+      etoolbar->priv->dnd_toolbar = NULL;
+      etoolbar->priv->dnd_toolitem = NULL;
+
+      /* If we don't have a name to use yet, try to create one. */
+      if (name == NULL && gtk_selection_data_get_length (selection_data) >= 0)
+        {
+          name = egg_toolbars_model_get_name (etoolbar->priv->model, type, data, TRUE);
+        }
+
+      if (name != NULL && !used)
+        {
+          gint tpos = get_toolbar_position (etoolbar, GTK_WIDGET (toolbar));
+          egg_toolbars_model_add_item (etoolbar->priv->model, tpos, ipos, name);
+          gtk_drag_finish (context, TRUE, gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE, time);
+        }
+      else
+        {
+          gtk_drag_finish (context, FALSE, gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE, time);
+        }
+    }
+
+  g_free (name);
+}
+
+static gboolean
+toolbar_drag_drop_cb (GtkToolbar         *toolbar,
+		      GdkDragContext     *context,
+		      gint                x,
+		      gint                y,
+		      guint               time,
+		      EggEditableToolbar *etoolbar)
+{
+  GdkAtom target;
+
+  target = gtk_drag_dest_find_target (GTK_WIDGET (toolbar), context, NULL);
+  if (target != GDK_NONE)
+    {
+      gtk_drag_get_data (GTK_WIDGET (toolbar), context, target, time);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+toolbar_drag_motion_cb (GtkToolbar         *toolbar,
+		        GdkDragContext     *context,
+		        gint                x,
+		        gint                y,
+		        guint               time,
+		        EggEditableToolbar *etoolbar)
+{
+  GdkAtom target = gtk_drag_dest_find_target (GTK_WIDGET (toolbar), context, NULL);
+  if (target == GDK_NONE)
+    {
+      gdk_drag_status (context, 0, time);
+      return FALSE;
+    }
+
+  /* Make ourselves the current dnd toolbar, and request a highlight item. */
+  if (etoolbar->priv->dnd_toolbar != toolbar)
+    {
+      etoolbar->priv->dnd_toolbar = toolbar;
+      etoolbar->priv->dnd_toolitem = NULL;
+      etoolbar->priv->dnd_pending++;
+      gtk_drag_get_data (GTK_WIDGET (toolbar), context, target, time);
+    }
+
+  /* If a highlight item is available, use it. */
+  else if (etoolbar->priv->dnd_toolitem)
+    {
+      gint ipos = gtk_toolbar_get_drop_index (etoolbar->priv->dnd_toolbar, x, y);
+      gtk_toolbar_set_drop_highlight_item (etoolbar->priv->dnd_toolbar,
+                                           etoolbar->priv->dnd_toolitem, ipos);
+    }
+
+  gdk_drag_status (context, gdk_drag_context_get_suggested_action (context), time);
+
+  return TRUE;
+}
+
+static void
+toolbar_drag_leave_cb (GtkToolbar         *toolbar,
+		       GdkDragContext     *context,
+		       guint               time,
+		       EggEditableToolbar *etoolbar)
+{
+  gtk_toolbar_set_drop_highlight_item (toolbar, NULL, 0);
+
+  /* If we were the current dnd toolbar target, remove the item. */
+  if (etoolbar->priv->dnd_toolbar == toolbar)
+    {
+      etoolbar->priv->dnd_toolbar = NULL;
+      etoolbar->priv->dnd_toolitem = NULL;
+    }
+}
+
+static void
+configure_drag_dest (EggEditableToolbar *etoolbar,
+                     GtkToolbar         *toolbar)
+{
+  EggToolbarsItemType *type;
+  GtkTargetList *targets;
+  GList *list;
+
+  /* Make every toolbar able to receive drag-drops. */
+  gtk_drag_dest_set (GTK_WIDGET (toolbar), 0,
+		     dest_drag_types, G_N_ELEMENTS (dest_drag_types),
+		     GDK_ACTION_MOVE | GDK_ACTION_COPY);
+
+  /* Add any specialist drag-drop abilities. */
+  targets = gtk_drag_dest_get_target_list (GTK_WIDGET (toolbar));
+  list = egg_toolbars_model_get_types (etoolbar->priv->model);
+  while (list)
+  {
+    type = list->data;
+    if (type->new_name != NULL || type->get_name != NULL)
+      gtk_target_list_add (targets, type->type, 0, 0);
+    list = list->next;
+  }
+}
+
+static void
+toggled_visibility_cb (GtkToggleAction *action,
+		       EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  GtkWidget *dock;
+  EggTbModelFlags flags;
+  gboolean visible;
+  gint i;
+
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+  visible = gtk_toggle_action_get_active (action);
+  G_GNUC_END_IGNORE_DEPRECATIONS;
+  for (i = 0; i < priv->visibility_actions->len; i++)
+    if (g_ptr_array_index (priv->visibility_actions, i) == action)
+      break;
+
+  g_return_if_fail (i < priv->visibility_actions->len);
+
+  dock = get_dock_nth (etoolbar, i);
+  if (visible)
+    {
+      gtk_widget_show (dock);
+    }
+  else
+    {
+      gtk_widget_hide (dock);
+    }
+
+  if (priv->save_hidden)
+    {
+      flags = egg_toolbars_model_get_flags (priv->model, i);
+
+      if (visible)
+        {
+	  flags &= ~(EGG_TB_MODEL_HIDDEN);
+	}
+      else
+	{
+	  flags |=  (EGG_TB_MODEL_HIDDEN);
+	}
+
+      egg_toolbars_model_set_flags (priv->model, i, flags);
+    }
+}
+
+static void
+toolbar_visibility_refresh (EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  gint n_toolbars, n_items, i, j, k;
+  GtkToggleAction *action;<--- Shadowed declaration
+  GList *list;
+  GString *string;
+  gboolean showing;
+  char action_name[40];
+  char *action_label;
+  char *tmp;
+
+  if (priv == NULL || priv->model == NULL || priv->manager == NULL ||
+      priv->visibility_paths == NULL || priv->actions == NULL)
+    {
+      return;
+    }
+
+  if (priv->visibility_actions == NULL)
+    {
+      priv->visibility_actions = g_ptr_array_new ();
+    }
+
+  if (priv->visibility_id != 0)
+    {
+      gtk_ui_manager_remove_ui (priv->manager, priv->visibility_id);
+    }
+
+  priv->visibility_id = gtk_ui_manager_new_merge_id (priv->manager);
+
+  showing = gtk_widget_get_visible (GTK_WIDGET (etoolbar));
+
+  n_toolbars = egg_toolbars_model_n_toolbars (priv->model);
+  for (i = 0; i < n_toolbars; i++)
+    {
+      string = g_string_sized_new (0);
+      n_items = egg_toolbars_model_n_items (priv->model, i);
+      for (k = 0, j = 0; j < n_items; j++)
+        {
+          GValue value = { 0, };
+          GtkAction *action;<--- Shadow variable
+          const char *name;
+
+          name = egg_toolbars_model_item_nth (priv->model, i, j);
+          if (name == NULL) continue;
+          action = find_action (etoolbar, name);
+          if (action == NULL) continue;
+
+          g_value_init (&value, G_TYPE_STRING);
+          g_object_get_property (G_OBJECT (action), "label", &value);
+          name = g_value_get_string (&value);
+          if (name == NULL)
+	    {
+		g_value_unset (&value);
+		continue;
+	    }
+	  k += g_utf8_strlen (name, -1) + 2;
+	  if (j > 0)
+	    {
+	      g_string_append (string, ", ");
+	      if (j > 1 && k > 25)
+		{
+		  g_value_unset (&value);
+		  break;
+		}
+	    }
+	  g_string_append (string, name);
+	  g_value_unset (&value);
+	}
+      if (j < n_items)
+        {
+	  g_string_append (string, " ...");
+        }
+
+      tmp = g_string_free (string, FALSE);
+      for (j = 0, k = 0; tmp[j]; j++)
+      {
+	if (tmp[j] == '_') continue;
+	tmp[k] = tmp[j];
+	k++;
+      }
+      tmp[k] = 0;
+      /* Translaters: This string is for a toggle to display a toolbar.
+       * The name of the toolbar is automatically computed from the widgets
+       * on the toolbar, and is placed at the %s. Note the _ before the %s
+       * which is used to add mnemonics. We know that this is likely to
+       * produce duplicates, but don't worry about it. If your language
+       * normally has a mnemonic at the start, please use the _. If not,
+       * please remove. */
+      action_label = g_strdup_printf (_("Show “_%s”"), tmp);
+      g_free (tmp);
+
+      sprintf(action_name, "ToolbarToggle%d", i);
+
+      if (i >= priv->visibility_actions->len)
+        {
+          G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+          action = gtk_toggle_action_new (action_name, action_label, NULL, NULL);
+          G_GNUC_END_IGNORE_DEPRECATIONS;
+          g_ptr_array_add (priv->visibility_actions, action);
+          g_signal_connect_object (action, "toggled",
+                                   G_CALLBACK (toggled_visibility_cb),
+                                   etoolbar, 0);
+          G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+          gtk_action_group_add_action (priv->actions, GTK_ACTION (action));
+          G_GNUC_END_IGNORE_DEPRECATIONS;          
+        }
+      else
+        {
+	  action = g_ptr_array_index (priv->visibility_actions, i);
+	  g_object_set (action, "label", action_label, NULL);
+        }
+
+      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+      gtk_action_set_visible (GTK_ACTION (action), (egg_toolbars_model_get_flags (priv->model, i)
+                                                    & EGG_TB_MODEL_NOT_REMOVABLE) == 0);
+      gtk_action_set_sensitive (GTK_ACTION (action), showing);
+      gtk_toggle_action_set_active (action, gtk_widget_get_visible
+                                    (get_dock_nth (etoolbar, i)));
+      G_GNUC_END_IGNORE_DEPRECATIONS;
+
+      for (list = priv->visibility_paths; list != NULL; list = g_list_next (list))
+        {
+	  gtk_ui_manager_add_ui (priv->manager, priv->visibility_id,
+				 (const char *)list->data, action_name, action_name,
+				 GTK_UI_MANAGER_MENUITEM, FALSE);
+	}
+
+      g_free (action_label);
+    }
+
+  gtk_ui_manager_ensure_update (priv->manager);
+
+  while (i < priv->visibility_actions->len)
+    {
+      action = g_ptr_array_index (priv->visibility_actions, i);
+      g_ptr_array_remove_index_fast (priv->visibility_actions, i);
+      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+      gtk_action_group_remove_action (priv->actions, GTK_ACTION (action));
+      G_GNUC_END_IGNORE_DEPRECATIONS;
+      i++;
+    }
+}
+
+static GtkWidget *
+create_dock (EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolbar, *hbox;
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+
+  toolbar = gtk_toolbar_new ();
+  gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), TRUE);
+  gtk_widget_show (toolbar);
+  gtk_box_pack_start (GTK_BOX (hbox), toolbar, TRUE, TRUE, 0);
+
+  g_signal_connect (toolbar, "drag_drop",
+		    G_CALLBACK (toolbar_drag_drop_cb), etoolbar);
+  g_signal_connect (toolbar, "drag_motion",
+		    G_CALLBACK (toolbar_drag_motion_cb), etoolbar);
+  g_signal_connect (toolbar, "drag_leave",
+		    G_CALLBACK (toolbar_drag_leave_cb), etoolbar);
+
+  g_signal_connect (toolbar, "drag_data_received",
+		    G_CALLBACK (toolbar_drag_data_received_cb), etoolbar);
+  g_signal_connect (toolbar, "popup_context_menu",
+		    G_CALLBACK (popup_context_menu_cb), etoolbar);
+
+  configure_drag_dest (etoolbar, GTK_TOOLBAR (toolbar));
+
+  return hbox;
+}
+
+static void
+set_fixed_style (EggEditableToolbar *t, GtkToolbarStyle style)
+{
+  g_return_if_fail (GTK_IS_TOOLBAR (t->priv->fixed_toolbar));
+  gtk_toolbar_set_style (GTK_TOOLBAR (t->priv->fixed_toolbar),
+  			 style == GTK_TOOLBAR_ICONS ? GTK_TOOLBAR_BOTH_HORIZ : style);
+}
+
+static void
+unset_fixed_style (EggEditableToolbar *t)
+{
+  g_return_if_fail (GTK_IS_TOOLBAR (t->priv->fixed_toolbar));
+  gtk_toolbar_unset_style (GTK_TOOLBAR (t->priv->fixed_toolbar));
+}
+
+static void
+toolbar_changed_cb (EggToolbarsModel   *model,
+	            int                 position,
+	            EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolbar;
+  EggTbModelFlags flags;
+  GtkToolbarStyle style;
+
+  flags = egg_toolbars_model_get_flags (model, position);
+  toolbar = get_toolbar_nth (etoolbar, position);
+
+  if (flags & EGG_TB_MODEL_ICONS)
+  {
+    style = GTK_TOOLBAR_ICONS;
+  }
+  else if (flags & EGG_TB_MODEL_TEXT)
+  {
+    style = GTK_TOOLBAR_TEXT;
+  }
+  else if (flags & EGG_TB_MODEL_BOTH)
+  {
+    style = GTK_TOOLBAR_BOTH;
+  }
+  else if (flags & EGG_TB_MODEL_BOTH_HORIZ)
+  {
+    style = GTK_TOOLBAR_BOTH_HORIZ;
+  }
+  else
+  {
+    gtk_toolbar_unset_style (GTK_TOOLBAR (toolbar));
+    if (position == 0 && etoolbar->priv->fixed_toolbar)
+      {
+        unset_fixed_style (etoolbar);
+      }
+    return;
+  }
+
+  gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), style);
+  if (position == 0 && etoolbar->priv->fixed_toolbar)
+    {
+      set_fixed_style (etoolbar, style);
+    }
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+static void
+unparent_fixed (EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolbar, *dock;
+  g_return_if_fail (GTK_IS_TOOLBAR (etoolbar->priv->fixed_toolbar));
+
+  toolbar = etoolbar->priv->fixed_toolbar;
+  dock = get_dock_nth (etoolbar, 0);
+
+  if (dock && gtk_widget_get_parent (toolbar) != NULL)
+    {
+      gtk_container_remove (GTK_CONTAINER (dock), toolbar);
+    }
+}
+
+static void
+update_fixed (EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolbar, *dock;
+  if (!etoolbar->priv->fixed_toolbar) return;
+
+  toolbar = etoolbar->priv->fixed_toolbar;
+  dock = get_dock_nth (etoolbar, 0);
+
+  if (dock && toolbar && gtk_widget_get_parent (toolbar) == NULL)
+    {
+      gtk_box_pack_end (GTK_BOX (dock), toolbar, FALSE, TRUE, 0);
+
+      gtk_widget_show (toolbar);
+
+      gtk_widget_set_size_request (dock, -1, -1);
+      gtk_widget_queue_resize_no_redraw (dock);
+    }
+}
+
+static void
+toolbar_added_cb (EggToolbarsModel   *model,
+	          int                 position,
+	          EggEditableToolbar *etoolbar)
+{
+  GtkWidget *dock;
+
+  dock = create_dock (etoolbar);
+  if ((egg_toolbars_model_get_flags (model, position) & EGG_TB_MODEL_HIDDEN) == 0)
+    gtk_widget_show (dock);
+
+  gtk_widget_set_size_request (dock, -1, MIN_TOOLBAR_HEIGHT);
+
+  gtk_box_pack_start (GTK_BOX (etoolbar), dock, TRUE, TRUE, 0);
+
+  gtk_box_reorder_child (GTK_BOX (etoolbar), dock, position);
+
+  gtk_widget_show_all (dock);
+
+  update_fixed (etoolbar);
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+static void
+toolbar_removed_cb (EggToolbarsModel   *model,
+	            int                 position,
+	            EggEditableToolbar *etoolbar)
+{
+  GtkWidget *dock;
+
+  if (position == 0 && etoolbar->priv->fixed_toolbar != NULL)
+    {
+      unparent_fixed (etoolbar);
+    }
+
+  dock = get_dock_nth (etoolbar, position);
+  gtk_widget_destroy (dock);
+
+  update_fixed (etoolbar);
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+static void
+item_added_cb (EggToolbarsModel   *model,
+	       int                 tpos,
+	       int                 ipos,
+	       EggEditableToolbar *etoolbar)
+{
+  GtkWidget *dock;
+  GtkWidget *toolbar;
+  GtkToolItem *item;
+
+  toolbar = get_toolbar_nth (etoolbar, tpos);
+  item = create_item_from_position (etoolbar, tpos, ipos);
+  if (item == NULL) return;
+
+  gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, ipos);
+
+  connect_widget_signals (GTK_WIDGET (item), etoolbar);
+  configure_item_tooltip (item);
+  configure_item_cursor (item, etoolbar);
+  configure_item_sensitivity (item, etoolbar);
+
+  dock = get_dock_nth (etoolbar, tpos);
+  gtk_widget_set_size_request (dock, -1, -1);
+  gtk_widget_queue_resize_no_redraw (dock);
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+static void
+item_removed_cb (EggToolbarsModel   *model,
+	         int                 toolbar_position,
+	         int                 position,
+	         EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+
+  GtkWidget *toolbar;
+  GtkWidget *item;
+
+  toolbar = get_toolbar_nth (etoolbar, toolbar_position);
+  item = GTK_WIDGET (gtk_toolbar_get_nth_item
+	(GTK_TOOLBAR (toolbar), position));
+  g_return_if_fail (item != NULL);
+
+  if (item == priv->selected)
+    {
+      /* FIXME */
+    }
+
+  gtk_container_remove (GTK_CONTAINER (toolbar), item);
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+static void
+egg_editable_toolbar_build (EggEditableToolbar *etoolbar)
+{
+  int i, l, n_items, n_toolbars;
+  EggToolbarsModel *model = etoolbar->priv->model;
+
+  g_return_if_fail (model != NULL);
+  g_return_if_fail (etoolbar->priv->manager != NULL);
+
+  n_toolbars = egg_toolbars_model_n_toolbars (model);
+
+  for (i = 0; i < n_toolbars; i++)
+    {
+      GtkWidget *toolbar, *dock;
+
+      dock = create_dock (etoolbar);
+      if ((egg_toolbars_model_get_flags (model, i) & EGG_TB_MODEL_HIDDEN) == 0)
+        gtk_widget_show (dock);
+      gtk_box_pack_start (GTK_BOX (etoolbar), dock, TRUE, TRUE, 0);
+      toolbar = get_toolbar_nth (etoolbar, i);
+
+      n_items = egg_toolbars_model_n_items (model, i);
+      for (l = 0; l < n_items; l++)
+        {
+          GtkToolItem *item;
+
+          item = create_item_from_position (etoolbar, i, l);
+          if (item)
+            {
+	      gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, l);
+
+              connect_widget_signals (GTK_WIDGET (item), etoolbar);
+	      configure_item_tooltip (item);
+              configure_item_sensitivity (item, etoolbar);
+            }
+          else
+            {
+              egg_toolbars_model_remove_item (model, i, l);
+              l--;
+              n_items--;
+            }
+        }
+
+      if (n_items == 0)
+        {
+            gtk_widget_set_size_request (dock, -1, MIN_TOOLBAR_HEIGHT);
+        }
+    }
+
+  update_fixed (etoolbar);
+
+  /* apply styles */
+  for (i = 0; i < n_toolbars; i ++)
+    {
+      toolbar_changed_cb (model, i, etoolbar);
+    }
+}
+
+static void
+egg_editable_toolbar_disconnect_model (EggEditableToolbar *toolbar)
+{
+  EggToolbarsModel *model = toolbar->priv->model;
+
+  g_signal_handlers_disconnect_by_func
+    (model, G_CALLBACK (item_added_cb), toolbar);
+  g_signal_handlers_disconnect_by_func
+    (model, G_CALLBACK (item_removed_cb), toolbar);
+  g_signal_handlers_disconnect_by_func
+    (model, G_CALLBACK (toolbar_added_cb), toolbar);
+  g_signal_handlers_disconnect_by_func
+    (model, G_CALLBACK (toolbar_removed_cb), toolbar);
+  g_signal_handlers_disconnect_by_func
+    (model, G_CALLBACK (toolbar_changed_cb), toolbar);
+}
+
+static void
+egg_editable_toolbar_deconstruct (EggEditableToolbar *toolbar)
+{
+  EggToolbarsModel *model = toolbar->priv->model;
+  GList *children;
+
+  g_return_if_fail (model != NULL);
+
+  if (toolbar->priv->fixed_toolbar)
+    {
+       unset_fixed_style (toolbar);
+       unparent_fixed (toolbar);
+    }
+
+  children = gtk_container_get_children (GTK_CONTAINER (toolbar));
+  g_list_free_full (children, (GDestroyNotify) gtk_widget_destroy);
+}
+
+void
+egg_editable_toolbar_set_model (EggEditableToolbar *etoolbar,
+				EggToolbarsModel   *model)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+
+  if (priv->model == model) return;
+
+  if (priv->model)
+    {
+      egg_editable_toolbar_disconnect_model (etoolbar);
+      egg_editable_toolbar_deconstruct (etoolbar);
+
+      g_object_unref (priv->model);
+    }
+
+  priv->model = g_object_ref (model);
+
+  egg_editable_toolbar_build (etoolbar);
+
+  toolbar_visibility_refresh (etoolbar);
+
+  g_signal_connect (model, "item_added",
+		    G_CALLBACK (item_added_cb), etoolbar);
+  g_signal_connect (model, "item_removed",
+		    G_CALLBACK (item_removed_cb), etoolbar);
+  g_signal_connect (model, "toolbar_added",
+		    G_CALLBACK (toolbar_added_cb), etoolbar);
+  g_signal_connect (model, "toolbar_removed",
+		    G_CALLBACK (toolbar_removed_cb), etoolbar);
+  g_signal_connect (model, "toolbar_changed",
+		    G_CALLBACK (toolbar_changed_cb), etoolbar);
+}
+
+static void
+egg_editable_toolbar_init (EggEditableToolbar *etoolbar)
+{
+  gtk_orientable_set_orientation (GTK_ORIENTABLE (etoolbar),
+                                  GTK_ORIENTATION_VERTICAL);
+
+  EggEditableToolbarPrivate *priv;
+
+  priv = etoolbar->priv = egg_editable_toolbar_get_instance_private (etoolbar);
+
+  priv->save_hidden = TRUE;
+
+  g_signal_connect (etoolbar, "notify::visible",
+		    G_CALLBACK (toolbar_visibility_refresh), NULL);
+}
+
+static void
+egg_editable_toolbar_dispose (GObject *object)
+{
+  EggEditableToolbar *etoolbar = EGG_EDITABLE_TOOLBAR (object);
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  GList *children;
+
+  if (priv->fixed_toolbar != NULL)
+    {
+      g_object_unref (priv->fixed_toolbar);
+      priv->fixed_toolbar = NULL;
+    }
+
+  if (priv->visibility_paths)
+    {
+      children = priv->visibility_paths;
+      g_list_free_full (children, g_free);
+      priv->visibility_paths = NULL;
+    }
+
+  g_free (priv->popup_path);
+  priv->popup_path = NULL;
+
+  if (priv->manager != NULL)
+    {
+      if (priv->visibility_id)
+        {
+	  gtk_ui_manager_remove_ui (priv->manager, priv->visibility_id);
+	  priv->visibility_id = 0;
+	}
+
+      g_object_unref (priv->manager);
+      priv->manager = NULL;
+    }
+
+  if (priv->model)
+    {
+      egg_editable_toolbar_disconnect_model (etoolbar);
+      g_object_unref (priv->model);
+      priv->model = NULL;
+    }
+
+  G_OBJECT_CLASS (egg_editable_toolbar_parent_class)->dispose (object);
+}
+
+static void
+egg_editable_toolbar_set_ui_manager (EggEditableToolbar *etoolbar,
+				     GtkUIManager       *manager)
+{
+  static const GtkActionEntry actions[] = {
+    { "MoveToolItem", STOCK_DRAG_MODE, N_("_Move on Toolbar"), NULL,
+      N_("Move the selected item on the toolbar"), G_CALLBACK (move_item_cb) },
+    { "RemoveToolItem", "list-remove", N_("_Remove from Toolbar"), NULL,
+      N_("Remove the selected item from the toolbar"), G_CALLBACK (remove_item_cb) },
+    { "RemoveToolbar", "edit-delete", N_("_Delete Toolbar"), NULL,
+      N_("Remove the selected toolbar"), G_CALLBACK (remove_toolbar_cb) },
+  };
+
+  etoolbar->priv->manager = g_object_ref (manager);
+
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+  etoolbar->priv->actions = gtk_action_group_new ("ToolbarActions");
+  gtk_action_group_set_translation_domain (etoolbar->priv->actions, GETTEXT_PACKAGE);
+  gtk_action_group_add_actions (etoolbar->priv->actions, actions,
+		 		G_N_ELEMENTS (actions), etoolbar);
+  G_GNUC_END_IGNORE_DEPRECATIONS;
+  gtk_ui_manager_insert_action_group (manager, etoolbar->priv->actions, -1);
+  g_object_unref (etoolbar->priv->actions);
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+GtkWidget * egg_editable_toolbar_get_selected (EggEditableToolbar   *etoolbar)
+{
+  return etoolbar->priv->selected;
+}
+
+void
+egg_editable_toolbar_set_selected (EggEditableToolbar *etoolbar,
+				   GtkWidget          *widget)
+{
+  GtkWidget *toolbar, *toolitem;
+  gboolean editable;
+
+  etoolbar->priv->selected = widget;
+
+  toolbar = (widget != NULL) ? gtk_widget_get_ancestor (widget, GTK_TYPE_TOOLBAR) : NULL;
+  toolitem = (widget != NULL) ? gtk_widget_get_ancestor (widget, GTK_TYPE_TOOL_ITEM) : NULL;
+
+  if(toolbar != NULL)
+    {
+      gint tpos = get_toolbar_position (etoolbar, toolbar);
+      editable = ((egg_toolbars_model_get_flags (etoolbar->priv->model, tpos) & EGG_TB_MODEL_NOT_EDITABLE) == 0);
+    }
+  else
+    {
+      editable = FALSE;
+    }
+
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+  gtk_action_set_visible (find_action (etoolbar, "RemoveToolbar"), (toolbar != NULL) && (etoolbar->priv->edit_mode > 0));
+  gtk_action_set_visible (find_action (etoolbar, "RemoveToolItem"), (toolitem != NULL) && editable);
+  gtk_action_set_visible (find_action (etoolbar, "MoveToolItem"), (toolitem != NULL) && editable);
+  G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+static void
+set_edit_mode (EggEditableToolbar *etoolbar,
+	       gboolean mode)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  int i, l, n_items;
+
+  i = priv->edit_mode;
+  if (mode)
+    {
+      priv->edit_mode++;
+    }
+  else
+    {
+      g_return_if_fail (priv->edit_mode > 0);
+      priv->edit_mode--;
+    }
+  i *= priv->edit_mode;
+
+  if (i == 0)
+    {
+      for (i = get_n_toolbars (etoolbar)-1; i >= 0; i--)
+        {
+          GtkWidget *toolbar;
+
+          toolbar = get_toolbar_nth (etoolbar, i);
+          n_items = gtk_toolbar_get_n_items (GTK_TOOLBAR (toolbar));
+
+          if (n_items == 0 && priv->edit_mode == 0)
+            {
+              egg_toolbars_model_remove_toolbar (priv->model, i);
+            }
+          else
+            {
+              for (l = 0; l < n_items; l++)
+                {
+                  GtkToolItem *item;
+
+                  item = gtk_toolbar_get_nth_item (GTK_TOOLBAR (toolbar), l);
+
+                  configure_item_cursor (item, etoolbar);
+                  configure_item_sensitivity (item, etoolbar);
+                }
+            }
+        }
+    }
+}
+
+static void
+egg_editable_toolbar_set_property (GObject      *object,
+				   guint         prop_id,
+				   const GValue *value,
+				   GParamSpec   *pspec)
+{
+  EggEditableToolbar *etoolbar = EGG_EDITABLE_TOOLBAR (object);
+
+  switch (prop_id)
+    {
+    case PROP_UI_MANAGER:
+      egg_editable_toolbar_set_ui_manager (etoolbar, g_value_get_object (value));
+      break;
+    case PROP_TOOLBARS_MODEL:
+      egg_editable_toolbar_set_model (etoolbar, g_value_get_object (value));
+      break;
+    case PROP_SELECTED:
+      egg_editable_toolbar_set_selected (etoolbar, g_value_get_object (value));
+      break;
+    case PROP_POPUP_PATH:
+      etoolbar->priv->popup_path = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_EDIT_MODE:
+      set_edit_mode (etoolbar, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+egg_editable_toolbar_get_property (GObject    *object,
+				   guint       prop_id,
+				   GValue     *value,
+				   GParamSpec *pspec)
+{
+  EggEditableToolbar *etoolbar = EGG_EDITABLE_TOOLBAR (object);
+
+  switch (prop_id)
+    {
+    case PROP_UI_MANAGER:
+      g_value_set_object (value, etoolbar->priv->manager);
+      break;
+    case PROP_TOOLBARS_MODEL:
+      g_value_set_object (value, etoolbar->priv->model);
+      break;
+    case PROP_SELECTED:
+      g_value_set_object (value, etoolbar->priv->selected);
+      break;
+    case PROP_EDIT_MODE:
+      g_value_set_boolean (value, etoolbar->priv->edit_mode>0);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+egg_editable_toolbar_class_init (EggEditableToolbarClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = egg_editable_toolbar_dispose;
+  object_class->set_property = egg_editable_toolbar_set_property;
+  object_class->get_property = egg_editable_toolbar_get_property;
+
+  egg_editable_toolbar_signals[ACTION_REQUEST] =
+    g_signal_new ("action_request",
+		  G_OBJECT_CLASS_TYPE (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (EggEditableToolbarClass, action_request),
+		  NULL, NULL, g_cclosure_marshal_VOID__STRING,
+		  G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  g_object_class_install_property (object_class,
+				   PROP_UI_MANAGER,
+				   g_param_spec_object ("ui-manager",
+							"UI-Mmanager",
+							"UI Manager",
+							GTK_TYPE_UI_MANAGER,
+							G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class,
+				   PROP_TOOLBARS_MODEL,
+				   g_param_spec_object ("model",
+							"Model",
+							"Toolbars Model",
+							EGG_TYPE_TOOLBARS_MODEL,
+							G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class,
+				   PROP_SELECTED,
+				   g_param_spec_object ("selected",
+							"Selected",
+							"Selected toolitem",
+							GTK_TYPE_TOOL_ITEM,
+							G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+  g_object_class_install_property (object_class,
+				   PROP_POPUP_PATH,
+				   g_param_spec_string ("popup-path",
+							"popup-path",
+							"popup-path",
+							NULL,
+							G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+  g_object_class_install_property (object_class,
+				   PROP_EDIT_MODE,
+				   g_param_spec_boolean ("edit-mode",
+							 "Edit-Mode",
+							 "Edit Mode",
+							 FALSE,
+							 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+}
+
+GtkWidget *
+egg_editable_toolbar_new (GtkUIManager *manager,
+                          const char *popup_path)
+{
+    return GTK_WIDGET (g_object_new (EGG_TYPE_EDITABLE_TOOLBAR,
+                                     "ui-manager", manager,
+                                     "popup-path", popup_path,
+                                     NULL));
+}
+
+GtkWidget *
+egg_editable_toolbar_new_with_model (GtkUIManager *manager,
+ 				     EggToolbarsModel *model,
+                                     const char *popup_path)
+{
+  return GTK_WIDGET (g_object_new (EGG_TYPE_EDITABLE_TOOLBAR,
+                                   "ui-manager", manager,
+                                   "model", model,
+                                   "popup-path", popup_path,
+				   NULL));
+}
+
+gboolean
+egg_editable_toolbar_get_edit_mode (EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+
+  return priv->edit_mode > 0;
+}
+
+void
+egg_editable_toolbar_set_edit_mode (EggEditableToolbar *etoolbar,
+				    gboolean mode)
+{
+  set_edit_mode (etoolbar, mode);
+  g_object_notify (G_OBJECT (etoolbar), "edit-mode");
+}
+
+void
+egg_editable_toolbar_add_visibility (EggEditableToolbar *etoolbar,
+				     const char *path)
+{
+  etoolbar->priv->visibility_paths = g_list_prepend
+	  (etoolbar->priv->visibility_paths, g_strdup (path));
+}
+
+void
+egg_editable_toolbar_show (EggEditableToolbar *etoolbar,
+			   const char *name)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  EggToolbarsModel *model = priv->model;
+  int i, n_toolbars;
+
+  n_toolbars = egg_toolbars_model_n_toolbars (model);
+  for (i = 0; i < n_toolbars; i++)
+    {
+      const char *toolbar_name;
+
+      toolbar_name = egg_toolbars_model_toolbar_nth (model, i);
+      if (strcmp (toolbar_name, name) == 0)
+        {
+          gtk_widget_show (get_dock_nth (etoolbar, i));
+        }
+    }
+}
+
+void
+egg_editable_toolbar_hide (EggEditableToolbar *etoolbar,
+			   const char *name)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  EggToolbarsModel *model = priv->model;
+  int i, n_toolbars;
+
+  n_toolbars = egg_toolbars_model_n_toolbars (model);
+  for (i = 0; i < n_toolbars; i++)
+    {
+      const char *toolbar_name;
+
+      toolbar_name = egg_toolbars_model_toolbar_nth (model, i);
+      if (strcmp (toolbar_name, name) == 0)
+      {
+        gtk_widget_hide (get_dock_nth (etoolbar, i));
+      }
+    }
+}
+
+void
+egg_editable_toolbar_set_fixed (EggEditableToolbar *etoolbar,
+				GtkToolbar *toolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+
+  g_return_if_fail (!toolbar || GTK_IS_TOOLBAR (toolbar));
+
+  if (priv->fixed_toolbar)
+    {
+      unparent_fixed (etoolbar);
+      g_object_unref (priv->fixed_toolbar);
+      priv->fixed_toolbar = NULL;
+    }
+
+  if (toolbar)
+    {
+      priv->fixed_toolbar = GTK_WIDGET (toolbar);
+      gtk_toolbar_set_show_arrow (toolbar, FALSE);
+      g_object_ref_sink (toolbar);
+    }
+
+  update_fixed (etoolbar);
+}
+
+#define DEFAULT_ICON_HEIGHT 20
+
+/* We should probably experiment some more with this.
+ * Right now the rendered icon is pretty good for most
+ * themes. However, the icon is slightly large for themes
+ * with large toolbar icons.
+ */
+static GdkPixbuf *
+new_pixbuf_from_widget (GtkWidget *widget)
+{
+  GtkWidget *window;
+  GdkPixbuf *pixbuf;
+  gint icon_height;
+
+  if (!gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR,
+                             NULL,
+                             &icon_height))
+    {
+      icon_height = DEFAULT_ICON_HEIGHT;
+    }
+
+  window = gtk_offscreen_window_new ();
+  /* Set the width to -1 as we want the separator to be as thin as possible. */
+  gtk_widget_set_size_request (widget, -1, icon_height);
+  gtk_container_add (GTK_CONTAINER (window), widget);
+  gtk_widget_show_all (window);
+
+  /* Process the waiting events to have the widget actually drawn */
+  gdk_window_process_updates (gtk_widget_get_window (window), TRUE);
+  pixbuf = gtk_offscreen_window_get_pixbuf (GTK_OFFSCREEN_WINDOW (window));
+  gtk_widget_destroy (window);
+
+  return pixbuf;
+}
+
+static GdkPixbuf *
+new_separator_pixbuf (void)
+{
+  GtkWidget *separator;
+  GdkPixbuf *pixbuf;
+
+  separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
+  pixbuf = new_pixbuf_from_widget (separator);
+  return pixbuf;
+}
+
+static void
+update_separator_image (GtkImage *image)
+{
+  GdkPixbuf *pixbuf = new_separator_pixbuf ();
+  gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+  g_object_unref (pixbuf);
+}
+
+static gboolean
+style_set_cb (GtkWidget *widget,
+              GtkStyle *previous_style,
+              GtkImage *image)
+{
+
+  update_separator_image (image);
+  return FALSE;
+}
+
+GtkWidget *
+_egg_editable_toolbar_new_separator_image (void)
+{
+  GtkWidget *image = gtk_image_new ();
+  update_separator_image (GTK_IMAGE (image));
+  g_signal_connect (G_OBJECT (image), "style_set",
+		    G_CALLBACK (style_set_cb), GTK_IMAGE (image));
+
+  return image;
+}
+
+EggToolbarsModel *
+egg_editable_toolbar_get_model (EggEditableToolbar *etoolbar)
+{
+  return etoolbar->priv->model;
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/1.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/1.html new file mode 100644 index 0000000..bc6aafc --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/1.html @@ -0,0 +1,1484 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
/*
+ *  Copyright (C) 2003 Marco Pesenti Gritti
+ *
+ *  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, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *  $Id: egg-toolbar-editor.c 929 2009-02-19 14:49:56Z friemann $
+ */
+
+#include "config.h"
+
+#include "egg-toolbar-editor.h"
+#include "egg-editable-toolbar.h"
+
+#include <string.h>
+#include <libxml/tree.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+static const GtkTargetEntry dest_drag_types[] = {
+  {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
+};
+
+static const GtkTargetEntry source_drag_types[] = {
+  {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
+};
+
+
+static void egg_toolbar_editor_finalize         (GObject *object);
+static void update_editor_sheet                 (EggToolbarEditor *editor);
+
+enum
+{
+  PROP_0,
+  PROP_UI_MANAGER,
+  PROP_TOOLBARS_MODEL
+};
+
+enum
+{
+  SIGNAL_HANDLER_ITEM_ADDED,
+  SIGNAL_HANDLER_ITEM_REMOVED,
+  SIGNAL_HANDLER_TOOLBAR_REMOVED,
+  SIGNAL_HANDLER_LIST_SIZE  /* Array size */
+};
+
+struct EggToolbarEditorPrivate
+{
+  GtkUIManager *manager;
+  EggToolbarsModel *model;
+
+  GtkWidget *grid;
+  GtkWidget *scrolled_window;
+  GList     *actions_list;
+  GList     *factory_list;
+
+  /* These handlers need to be sanely disconnected when switching models */
+  gulong     sig_handlers[SIGNAL_HANDLER_LIST_SIZE];
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (EggToolbarEditor, egg_toolbar_editor, GTK_TYPE_BOX)
+
+static gint
+compare_items (gconstpointer a,
+               gconstpointer b)
+{
+  const GtkWidget *item1 = a;
+  const GtkWidget *item2 = b;
+
+  char *key1 = g_object_get_data (G_OBJECT (item1),
+                                  "egg-collate-key");
+  char *key2 = g_object_get_data (G_OBJECT (item2),
+                                  "egg-collate-key");
+
+  return strcmp (key1, key2);
+}
+
+static GtkAction *
+find_action (EggToolbarEditor *t,
+	     const char       *name)
+{
+  GList *l;
+  GtkAction *action = NULL;
+
+  l = gtk_ui_manager_get_action_groups (t->priv->manager);
+
+  g_return_val_if_fail (EGG_IS_TOOLBAR_EDITOR (t), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  for (; l != NULL; l = l->next)
+    {
+      GtkAction *tmp;
+
+      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+      tmp = gtk_action_group_get_action (GTK_ACTION_GROUP (l->data), name);
+      G_GNUC_END_IGNORE_DEPRECATIONS;
+      if (tmp)
+	action = tmp;
+    }
+
+  return action;
+}
+
+static void
+egg_toolbar_editor_set_ui_manager (EggToolbarEditor *t,
+				   GtkUIManager     *manager)
+{
+  g_return_if_fail (GTK_IS_UI_MANAGER (manager));
+
+  t->priv->manager = g_object_ref (manager);
+}
+
+static void
+item_added_or_removed_cb (EggToolbarsModel   *model,
+                          int                 tpos,
+                          int                 ipos,
+                          EggToolbarEditor   *editor)
+{
+  update_editor_sheet (editor);
+}
+
+static void
+toolbar_removed_cb (EggToolbarsModel   *model,
+	            int                 position,
+	            EggToolbarEditor   *editor)
+{
+  update_editor_sheet (editor);
+}
+
+static void
+egg_toolbar_editor_disconnect_model (EggToolbarEditor *t)
+{
+  EggToolbarEditorPrivate *priv = t->priv;
+  EggToolbarsModel *model = priv->model;
+  gulong handler;
+  int i;
+
+  for (i = 0; i < SIGNAL_HANDLER_LIST_SIZE; i++)
+    {
+      handler = priv->sig_handlers[i];
+
+      if (handler != 0)
+        {
+	  if (g_signal_handler_is_connected (model, handler))
+	    {
+	      g_signal_handler_disconnect (model, handler);
+	    }
+
+	  priv->sig_handlers[i] = 0;
+        }
+    }
+}
+
+void
+egg_toolbar_editor_set_model (EggToolbarEditor *t,
+			      EggToolbarsModel *model)
+{
+  EggToolbarEditorPrivate *priv;
+
+  g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (t));
+  g_return_if_fail (model != NULL);
+
+  priv = t->priv;
+
+  if (priv->model)
+    {
+      if (G_UNLIKELY (priv->model == model)) return;
+
+      egg_toolbar_editor_disconnect_model (t);
+      g_object_unref (priv->model);
+    }
+
+  priv->model = g_object_ref (model);
+
+  update_editor_sheet (t);
+
+  priv->sig_handlers[SIGNAL_HANDLER_ITEM_ADDED] =
+    g_signal_connect_object (model, "item_added",
+			     G_CALLBACK (item_added_or_removed_cb), t, 0);
+  priv->sig_handlers[SIGNAL_HANDLER_ITEM_REMOVED] =
+    g_signal_connect_object (model, "item_removed",
+			     G_CALLBACK (item_added_or_removed_cb), t, 0);
+  priv->sig_handlers[SIGNAL_HANDLER_TOOLBAR_REMOVED] =
+    g_signal_connect_object (model, "toolbar_removed",
+			     G_CALLBACK (toolbar_removed_cb), t, 0);
+}
+
+static void
+egg_toolbar_editor_set_property (GObject      *object,
+				 guint         prop_id,
+				 const GValue *value,
+				 GParamSpec   *pspec)
+{
+  EggToolbarEditor *t = EGG_TOOLBAR_EDITOR (object);
+
+  switch (prop_id)
+    {
+    case PROP_UI_MANAGER:
+      egg_toolbar_editor_set_ui_manager (t, g_value_get_object (value));
+      break;
+    case PROP_TOOLBARS_MODEL:
+      egg_toolbar_editor_set_model (t, g_value_get_object (value));
+      break;
+    }
+}
+
+static void
+egg_toolbar_editor_get_property (GObject    *object,
+				 guint       prop_id,
+				 GValue     *value,
+				 GParamSpec *pspec)
+{
+  EggToolbarEditor *t = EGG_TOOLBAR_EDITOR (object);
+
+  switch (prop_id)
+    {
+    case PROP_UI_MANAGER:
+      g_value_set_object (value, t->priv->manager);
+      break;
+    case PROP_TOOLBARS_MODEL:
+      g_value_set_object (value, t->priv->model);
+      break;
+    }
+}
+
+static void
+egg_toolbar_editor_class_init (EggToolbarEditorClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = egg_toolbar_editor_finalize;
+  object_class->set_property = egg_toolbar_editor_set_property;
+  object_class->get_property = egg_toolbar_editor_get_property;
+
+  g_object_class_install_property (object_class,
+				   PROP_UI_MANAGER,
+				   g_param_spec_object ("ui-manager",
+							"UI-Manager",
+							"UI Manager",
+							GTK_TYPE_UI_MANAGER,
+							G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+							G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+				  PROP_TOOLBARS_MODEL,
+				  g_param_spec_object ("model",
+						       "Model",
+						       "Toolbars Model",
+						       EGG_TYPE_TOOLBARS_MODEL,
+						       G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+						       G_PARAM_CONSTRUCT));
+
+  GtkWidgetClass *widget_class  = GTK_WIDGET_CLASS (klass);
+  gtk_widget_class_set_css_name (widget_class, "EggToolbarEditor");
+}
+
+static void
+egg_toolbar_editor_finalize (GObject *object)
+{
+  EggToolbarEditor *editor = EGG_TOOLBAR_EDITOR (object);
+
+  if (editor->priv->manager)
+    {
+      g_object_unref (editor->priv->manager);
+    }
+
+  if (editor->priv->model)
+    {
+      egg_toolbar_editor_disconnect_model (editor);
+      g_object_unref (editor->priv->model);
+    }
+
+  g_list_free (editor->priv->actions_list);
+  g_list_free (editor->priv->factory_list);
+
+  G_OBJECT_CLASS (egg_toolbar_editor_parent_class)->finalize (object);
+}
+
+GtkWidget *
+egg_toolbar_editor_new (GtkUIManager *manager,
+			EggToolbarsModel *model)
+{
+  return GTK_WIDGET (g_object_new (EGG_TYPE_TOOLBAR_EDITOR,
+				   "ui-manager", manager,
+				   "model", model,
+				   NULL));
+}
+
+static void
+drag_begin_cb (GtkWidget          *widget,
+	       GdkDragContext     *context)
+{
+  gtk_widget_hide (widget);
+}
+
+static void
+drag_end_cb (GtkWidget          *widget,
+	     GdkDragContext     *context)
+{
+  gtk_widget_show (widget);
+}
+
+static void
+drag_data_get_cb (GtkWidget          *widget,
+		  GdkDragContext     *context,
+		  GtkSelectionData   *selection_data,
+		  guint               info,
+		  guint32             time,
+		  EggToolbarEditor   *editor)
+{
+  const char *target;
+
+  target = g_object_get_data (G_OBJECT (widget), "egg-item-name");
+  g_return_if_fail (target != NULL);
+
+  gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8,
+			  (const guchar *) target, strlen (target));
+}
+
+static gchar *
+elide_underscores (const gchar *original)
+{
+  gchar *q, *result;
+  const gchar *p;
+  gboolean last_underscore;
+
+  q = result = g_malloc (strlen (original) + 1);
+  last_underscore = FALSE;
+
+  for (p = original; *p; p++)
+    {
+      if (!last_underscore && *p == '_')
+	last_underscore = TRUE;
+      else
+	{
+	  last_underscore = FALSE;
+	  *q++ = *p;
+	}
+    }
+
+  *q = '\0';
+
+  return result;
+}
+
+static void
+set_drag_cursor (GtkWidget *widget)
+{
+  GdkCursor *cursor;
+  GdkScreen *screen;
+
+  screen = gtk_widget_get_screen (widget);
+
+  cursor = gdk_cursor_new_for_display (gdk_screen_get_display (screen),
+				       GDK_HAND2);
+  gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
+  g_object_unref (cursor);
+}
+
+static void
+event_box_realize_cb (GtkWidget *widget, GtkImage *icon)
+{
+  GtkImageType type;
+
+  set_drag_cursor (widget);
+
+  type = gtk_image_get_storage_type (icon);
+  if (type == GTK_IMAGE_STOCK)
+    {
+      gchar *stock_id;
+      GdkPixbuf *pixbuf;
+
+      gtk_image_get_stock (icon, &stock_id, NULL);
+      pixbuf = gtk_widget_render_icon (widget, stock_id,
+	                               GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
+      gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
+      g_object_unref (pixbuf);
+    }
+  else if (type == GTK_IMAGE_ICON_NAME)
+    {
+      const gchar *icon_name;
+      GdkScreen *screen;
+      GtkIconTheme *icon_theme;
+      gint width, height;
+      GdkPixbuf *pixbuf;
+
+      gtk_image_get_icon_name (icon, &icon_name, NULL);
+      screen = gtk_widget_get_screen (widget);
+      icon_theme = gtk_icon_theme_get_for_screen (screen);
+
+      if (!gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR,
+                                 &width, &height))
+        {
+	  width = height = 24;
+	}
+
+      pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name,
+                                         MIN (width, height), 0, NULL);
+      if (G_UNLIKELY (!pixbuf))
+        return;
+
+      gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
+      g_object_unref (pixbuf);
+
+    }
+  else if (type == GTK_IMAGE_PIXBUF)
+    {
+      GdkPixbuf *pixbuf = gtk_image_get_pixbuf (icon);
+      gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
+    }
+}
+
+static GtkWidget *
+editor_create_item (EggToolbarEditor *editor,
+		    GtkImage	     *icon,
+		    const char       *label_text,
+		    GdkDragAction     action)
+{
+  GtkWidget *event_box;
+  GtkWidget *vbox;
+  GtkWidget *label;
+  gchar *label_no_mnemonic = NULL;
+
+  event_box = gtk_event_box_new ();
+  gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
+  gtk_widget_show (event_box);
+  gtk_drag_source_set (event_box,
+		       GDK_BUTTON1_MASK,
+		       source_drag_types, G_N_ELEMENTS (source_drag_types), action);
+  g_signal_connect (event_box, "drag_data_get",
+		    G_CALLBACK (drag_data_get_cb), editor);
+  g_signal_connect_after (event_box, "realize",
+		          G_CALLBACK (event_box_realize_cb), icon);
+
+  if (action == GDK_ACTION_MOVE)
+    {
+      g_signal_connect (event_box, "drag_begin",
+		        G_CALLBACK (drag_begin_cb), NULL);
+      g_signal_connect (event_box, "drag_end",
+		        G_CALLBACK (drag_end_cb), NULL);
+    }
+
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+  gtk_widget_show (vbox);
+  gtk_container_add (GTK_CONTAINER (event_box), vbox);
+
+  gtk_widget_show (GTK_WIDGET (icon));
+  gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (icon), FALSE, TRUE, 0);
+  label_no_mnemonic = elide_underscores (label_text);
+  label = gtk_label_new (label_no_mnemonic);
+  g_free (label_no_mnemonic);
+  gtk_widget_show (label);
+  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
+
+  return event_box;
+}
+
+static GtkWidget *
+editor_create_item_from_name (EggToolbarEditor *editor,
+                              const char *      name,
+                              GdkDragAction     drag_action)
+{
+  GtkWidget *item;
+  const char *item_name;
+  char *short_label;
+  const char *collate_key;
+
+  if (strcmp (name, "_separator") == 0)
+    {
+      GtkWidget *icon;
+
+      icon = _egg_editable_toolbar_new_separator_image ();
+      short_label = _("Separator");
+      item_name = g_strdup (name);
+      collate_key = g_utf8_collate_key (short_label, -1);
+      item = editor_create_item (editor, GTK_IMAGE (icon),
+                                 short_label, drag_action);
+    }
+  else
+    {
+      GtkAction *action;
+      GtkWidget *icon;
+      char *stock_id, *icon_name = NULL;
+
+      action = find_action (editor, name);
+      g_return_val_if_fail (action != NULL, NULL);
+
+      g_object_get (action,
+                    "icon-name", &icon_name,
+                    "stock-id", &stock_id,
+		    "short-label", &short_label,
+		    NULL);
+
+      /* This is a workaround to catch named icons. */
+      if (icon_name)
+        icon = gtk_image_new_from_icon_name (icon_name,
+	                                     GTK_ICON_SIZE_LARGE_TOOLBAR);
+      else
+        icon = gtk_image_new_from_icon_name (stock_id ? stock_id : "gtk-dnd",
+                                             GTK_ICON_SIZE_LARGE_TOOLBAR);
+
+      item_name = g_strdup (name);
+      collate_key = g_utf8_collate_key (short_label, -1);
+      item = editor_create_item (editor, GTK_IMAGE (icon),
+                                 short_label, drag_action);
+
+      g_free (short_label);
+      g_free (stock_id);
+      g_free (icon_name);
+    }
+
+  g_object_set_data_full (G_OBJECT (item), "egg-collate-key",
+                          (gpointer) collate_key, g_free);
+  g_object_set_data_full (G_OBJECT (item), "egg-item-name",
+                          (gpointer) item_name, g_free);
+
+  return item;
+}
+
+static gint
+append_grid (GtkGrid *grid, GList *items, gint y, gint width)
+{
+  if (items != NULL)
+    {
+      gint x = 0;
+      GtkWidget *item;
+
+      if (y > 0)
+        {
+          item = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+          gtk_widget_set_hexpand (item, TRUE);
+          gtk_widget_set_vexpand (item, FALSE);
+          gtk_widget_show (item);
+
+          gtk_grid_attach (grid, item, 0, y, width, 1);
+          y++;
+        }
+
+      for (; items != NULL; items = items->next)
+        {
+          item = items->data;
+          gtk_widget_set_hexpand (item, FALSE);
+          gtk_widget_set_vexpand (item, FALSE);
+          gtk_widget_show (item);
+
+          if (x >= width)
+            {
+              x = 0;
+              y++;
+            }
+          gtk_grid_attach (grid, item, x, y, 1, 1);
+          x++;
+        }
+
+      y++;
+    }
+  return y;
+}
+
+static void
+update_editor_sheet (EggToolbarEditor *editor)
+{
+  gint y;
+  GPtrArray *items;
+  GList *to_move = NULL, *to_copy = NULL;
+  GtkWidget *grid;
+  GtkWidget *viewport;
+
+  g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (editor));
+
+  /* Create new grid. */
+  grid = gtk_grid_new ();
+  editor->priv->grid = grid;
+  gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
+  gtk_grid_set_row_spacing (GTK_GRID (grid), 24);
+  gtk_widget_show (grid);
+  gtk_drag_dest_set (grid, GTK_DEST_DEFAULT_ALL,
+		     dest_drag_types, G_N_ELEMENTS (dest_drag_types),
+                     GDK_ACTION_MOVE | GDK_ACTION_COPY);
+
+  /* Build two lists of items (one for copying, one for moving). */
+  items = egg_toolbars_model_get_name_avail (editor->priv->model);
+  while (items->len > 0)
+    {
+      GtkWidget *item;
+      const char *name;
+      gint flags;
+
+      name = g_ptr_array_index (items, 0);
+      g_ptr_array_remove_index_fast (items, 0);
+
+      flags = egg_toolbars_model_get_name_flags (editor->priv->model, name);
+      if ((flags & EGG_TB_MODEL_NAME_INFINITE) == 0)
+        {
+          item = editor_create_item_from_name (editor, name, GDK_ACTION_MOVE);
+          if (item != NULL)
+            to_move = g_list_insert_sorted (to_move, item, compare_items);
+        }
+      else
+        {
+          item = editor_create_item_from_name (editor, name, GDK_ACTION_COPY);
+          if (item != NULL)
+            to_copy = g_list_insert_sorted (to_copy, item, compare_items);
+        }
+    }
+
+  /* Add them to the sheet. */
+  y = 0;
+  y = append_grid (GTK_GRID (grid), to_move, y, 4);
+  y = append_grid (GTK_GRID (grid), to_copy, y, 4);<--- Variable 'y' is assigned a value that is never used.
+
+  g_list_free (to_move);
+  g_list_free (to_copy);
+  g_ptr_array_free (items, TRUE);
+
+  /* Delete old table/grid. */
+  viewport = gtk_bin_get_child (GTK_BIN (editor->priv->scrolled_window));
+  if (viewport)
+    {
+      gtk_container_remove (GTK_CONTAINER (viewport),
+                            gtk_bin_get_child (GTK_BIN (viewport)));
+    }
+
+  /* Add grid to window. */
+  gtk_scrolled_window_add_with_viewport
+    (GTK_SCROLLED_WINDOW (editor->priv->scrolled_window), grid);
+}
+
+static void
+setup_editor (EggToolbarEditor *editor)
+{
+  GtkWidget *scrolled_window;
+
+  gtk_orientable_set_orientation (GTK_ORIENTABLE (editor),
+                                  GTK_ORIENTATION_VERTICAL);
+
+  gtk_container_set_border_width (GTK_CONTAINER (editor), 12);
+  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+  editor->priv->scrolled_window = scrolled_window;
+  gtk_widget_show (scrolled_window);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+				  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  gtk_box_pack_start (GTK_BOX (editor), scrolled_window, TRUE, TRUE, 0);
+}
+
+static void
+egg_toolbar_editor_init (EggToolbarEditor *t)
+{
+  t->priv = egg_toolbar_editor_get_instance_private (t);
+
+  t->priv->manager = NULL;
+  t->priv->actions_list = NULL;
+
+  setup_editor (t);
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/10.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/10.html new file mode 100644 index 0000000..f45e7a7 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/10.html @@ -0,0 +1,5122 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+2145
+2146
+2147
+2148
+2149
+2150
+2151
+2152
+2153
+2154
+2155
+2156
+2157
+2158
+2159
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2180
+2181
+2182
+2183
+2184
+2185
+2186
+2187
+2188
+2189
+2190
+2191
+2192
+2193
+2194
+2195
+2196
+2197
+2198
+2199
+2200
+2201
+2202
+2203
+2204
+2205
+2206
+2207
+2208
+2209
+2210
+2211
+2212
+2213
+2214
+2215
+2216
+2217
+2218
+2219
+2220
+2221
+2222
+2223
+2224
+2225
+2226
+2227
+2228
+2229
+2230
+2231
+2232
+2233
+2234
+2235
+2236
+2237
+2238
+2239
+2240
+2241
+2242
+2243
+2244
+2245
+2246
+2247
+2248
+2249
+2250
+2251
+2252
+2253
+2254
+2255
+2256
+2257
+2258
+2259
+2260
+2261
+2262
+2263
+2264
+2265
+2266
+2267
+2268
+2269
+2270
+2271
+2272
+2273
+2274
+2275
+2276
+2277
+2278
+2279
+2280
+2281
+2282
+2283
+2284
+2285
+2286
+2287
+2288
+2289
+2290
+2291
+2292
+2293
+2294
+2295
+2296
+2297
+2298
+2299
+2300
+2301
+2302
+2303
+2304
+2305
+2306
+2307
+2308
+2309
+2310
+2311
+2312
+2313
+2314
+2315
+2316
+2317
+2318
+2319
+2320
+2321
+2322
+2323
+2324
+2325
+2326
+2327
+2328
+2329
+2330
+2331
+2332
+2333
+2334
+2335
+2336
+2337
+2338
+2339
+2340
+2341
+2342
+2343
+2344
+2345
+2346
+2347
+2348
+2349
+2350
+2351
+2352
+2353
+2354
+2355
+2356
+2357
+2358
+2359
+2360
+2361
+2362
+2363
+2364
+2365
+2366
+2367
+2368
+2369
+2370
+2371
+2372
+2373
+2374
+2375
+2376
+2377
+2378
+2379
+2380
+2381
+2382
+2383
+2384
+2385
+2386
+2387
+2388
+2389
+2390
+2391
+2392
+2393
+2394
+2395
+2396
+2397
+2398
+2399
+2400
+2401
+2402
+2403
+2404
+2405
+2406
+2407
+2408
+2409
+2410
+2411
+2412
+2413
+2414
+2415
+2416
+2417
+2418
+2419
+2420
+2421
+2422
+2423
+2424
+2425
+2426
+2427
+2428
+2429
+2430
+2431
+2432
+2433
+2434
+2435
+2436
+2437
+2438
+2439
+2440
+2441
+2442
+2443
+2444
+2445
+2446
+2447
+2448
/* Eye Of Mate - Image
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <lucasr@gnome.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define GDK_PIXBUF_ENABLE_BACKEND
+#include <gdk/gdkx.h>
+
+#include "eom-image.h"
+#include "eom-image-private.h"
+#include "eom-debug.h"
+
+#ifdef HAVE_JPEG
+#include "eom-image-jpeg.h"
+#endif
+
+#include "eom-marshal.h"
+#include "eom-pixbuf-util.h"
+#include "eom-metadata-reader.h"
+#include "eom-image-save-info.h"
+#include "eom-transform.h"
+#include "eom-util.h"
+#include "eom-jobs.h"
+#include "eom-thumbnail.h"
+
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#ifdef HAVE_EXIF
+#include "eom-exif-util.h"
+#include <libexif/exif-data.h>
+#include <libexif/exif-utils.h>
+#include <libexif/exif-loader.h>
+#endif
+
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+#include <lcms2.h>
+#ifndef EXIF_TAG_GAMMA
+#define EXIF_TAG_GAMMA 0xa500
+#endif
+#endif
+
+#ifdef HAVE_RSVG
+#include <librsvg/rsvg.h>
+#endif
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomImage, eom_image, G_TYPE_OBJECT)
+
+enum {
+	SIGNAL_CHANGED,
+	SIGNAL_SIZE_PREPARED,
+	SIGNAL_THUMBNAIL_CHANGED,
+	SIGNAL_SAVE_PROGRESS,
+	SIGNAL_NEXT_FRAME,
+	SIGNAL_FILE_CHANGED,
+	SIGNAL_LAST
+};
+
+static guint signals[SIGNAL_LAST] = { 0 };
+
+static GList *supported_mime_types = NULL;<--- Shadowed declaration
+
+#define EOM_IMAGE_READ_BUFFER_SIZE 65535
+
+static void
+eom_image_free_mem_private (EomImage *image)
+{
+	EomImagePrivate *priv;
+
+	priv = image->priv;
+
+	if (priv->status == EOM_IMAGE_STATUS_LOADING) {
+		eom_image_cancel_load (image);
+	} else {
+		if (priv->anim_iter != NULL) {
+			g_object_unref (priv->anim_iter);
+			priv->anim_iter = NULL;
+		}
+
+		if (priv->anim != NULL) {
+			g_object_unref (priv->anim);
+			priv->anim = NULL;
+		}
+
+		priv->is_playing = FALSE;
+
+		if (priv->image != NULL) {
+			g_object_unref (priv->image);
+			priv->image = NULL;
+		}
+
+#ifdef HAVE_RSVG
+		if (priv->svg != NULL) {
+			g_object_unref (priv->svg);
+			priv->svg = NULL;
+		}
+#endif
+
+#ifdef HAVE_EXIF
+		if (priv->exif != NULL) {
+			exif_data_unref (priv->exif);
+			priv->exif = NULL;
+		}
+#endif
+
+		if (priv->exif_chunk != NULL) {
+			g_free (priv->exif_chunk);
+			priv->exif_chunk = NULL;
+		}
+
+		priv->exif_chunk_len = 0;
+
+#ifdef HAVE_EXEMPI
+		if (priv->xmp != NULL) {
+			xmp_free (priv->xmp);
+			priv->xmp = NULL;
+		}
+#endif
+
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+		if (priv->profile != NULL) {
+			if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
+				cmsCloseProfile (priv->profile);
+			}
+			priv->profile = NULL;
+		}
+#endif
+
+		priv->status = EOM_IMAGE_STATUS_UNKNOWN;
+		priv->metadata_status = EOM_IMAGE_METADATA_NOT_READ;
+	}
+}
+
+static void
+eom_image_dispose (GObject *object)
+{
+	EomImagePrivate *priv;
+
+	priv = EOM_IMAGE (object)->priv;
+
+	eom_image_free_mem_private (EOM_IMAGE (object));
+
+	if (priv->file) {
+		g_object_unref (priv->file);
+		priv->file = NULL;
+	}
+
+	if (priv->caption) {
+		g_free (priv->caption);
+		priv->caption = NULL;
+	}
+
+	if (priv->collate_key) {
+		g_free (priv->collate_key);
+		priv->collate_key = NULL;
+	}
+
+	if (priv->file_type) {
+		g_free (priv->file_type);
+		priv->file_type = NULL;
+	}
+
+	g_mutex_clear (&priv->status_mutex);
+
+	if (priv->trans) {
+		g_object_unref (priv->trans);
+		priv->trans = NULL;
+	}
+
+	if (priv->trans_autorotate) {
+		g_object_unref (priv->trans_autorotate);
+		priv->trans_autorotate = NULL;
+	}
+
+	if (priv->undo_stack) {
+		g_slist_free_full (priv->undo_stack, g_object_unref);
+		priv->undo_stack = NULL;
+	}
+
+	G_OBJECT_CLASS (eom_image_parent_class)->dispose (object);
+}
+
+static void
+eom_image_class_init (EomImageClass *klass)
+{
+	GObjectClass *object_class = (GObjectClass*) klass;
+
+	object_class->dispose = eom_image_dispose;
+
+	signals[SIGNAL_SIZE_PREPARED] =
+		g_signal_new ("size-prepared",
+			      EOM_TYPE_IMAGE,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EomImageClass, size_prepared),
+			      NULL, NULL,
+			      eom_marshal_VOID__INT_INT,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_INT,
+			      G_TYPE_INT);
+
+	signals[SIGNAL_CHANGED] =
+		g_signal_new ("changed",
+			      EOM_TYPE_IMAGE,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EomImageClass, changed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+
+	signals[SIGNAL_THUMBNAIL_CHANGED] =
+		g_signal_new ("thumbnail-changed",
+			      EOM_TYPE_IMAGE,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EomImageClass, thumbnail_changed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+
+	signals[SIGNAL_SAVE_PROGRESS] =
+		g_signal_new ("save-progress",
+			      EOM_TYPE_IMAGE,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EomImageClass, save_progress),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__FLOAT,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_FLOAT);
+ 	/**
+ 	 * EomImage::next-frame:
+  	 * @img: the object which received the signal.
+	 * @delay: number of milliseconds the current frame will be displayed.
+	 *
+	 * The ::next-frame signal will be emitted each time an animated image
+	 * advances to the next frame.
+	 */
+	signals[SIGNAL_NEXT_FRAME] =
+		g_signal_new ("next-frame",
+			      EOM_TYPE_IMAGE,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EomImageClass, next_frame),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__INT,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_INT);
+
+	signals[SIGNAL_FILE_CHANGED] = g_signal_new ("file-changed",
+						     EOM_TYPE_IMAGE,
+						     G_SIGNAL_RUN_LAST,
+						     G_STRUCT_OFFSET (EomImageClass, file_changed),
+						     NULL, NULL,
+						     g_cclosure_marshal_VOID__VOID,
+						     G_TYPE_NONE, 0);
+}
+
+static void
+eom_image_init (EomImage *img)
+{
+	img->priv = eom_image_get_instance_private (img);
+
+	img->priv->file = NULL;
+	img->priv->image = NULL;
+	img->priv->anim = NULL;
+	img->priv->anim_iter = NULL;
+	img->priv->is_playing = FALSE;
+	img->priv->thumbnail = NULL;
+	img->priv->width = -1;
+	img->priv->height = -1;
+	img->priv->modified = FALSE;
+	img->priv->file_is_changed = FALSE;
+	g_mutex_init (&img->priv->status_mutex);
+	img->priv->status = EOM_IMAGE_STATUS_UNKNOWN;
+	img->priv->metadata_status = EOM_IMAGE_METADATA_NOT_READ;
+	img->priv->undo_stack = NULL;
+	img->priv->trans = NULL;
+	img->priv->trans_autorotate = NULL;
+	img->priv->data_ref_count = 0;
+#ifdef HAVE_EXIF
+	img->priv->orientation = 0;
+	img->priv->autorotate = FALSE;
+	img->priv->exif = NULL;
+#endif
+#ifdef HAVE_EXEMPI
+	img->priv->xmp = NULL;
+#endif
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+	img->priv->profile = NULL;
+#endif
+#ifdef HAVE_RSVG
+	img->priv->svg = NULL;
+#endif
+}
+
+EomImage *
+eom_image_new_file (GFile *file, const gchar *caption)
+{
+	EomImage *img;
+
+	img = EOM_IMAGE (g_object_new (EOM_TYPE_IMAGE, NULL));
+
+	img->priv->file = g_object_ref (file);
+	img->priv->caption = g_strdup (caption);
+
+	return img;
+}
+
+GQuark
+eom_image_error_quark (void)
+{
+	static GQuark q = 0;
+
+	if (q == 0) {
+		q = g_quark_from_static_string ("eom-image-error-quark");
+	}
+
+	return q;
+}
+
+static void
+eom_image_update_exif_data (EomImage *image)
+{
+#ifdef HAVE_EXIF
+	EomImagePrivate *priv;
+	ExifEntry *entry;
+	ExifByteOrder bo;
+
+	eom_debug (DEBUG_IMAGE_DATA);
+
+	g_return_if_fail (EOM_IS_IMAGE (image));
+
+	priv = image->priv;
+
+	if (priv->exif == NULL) return;
+
+	bo = exif_data_get_byte_order (priv->exif);
+
+	/* Update image width */
+	entry = exif_data_get_entry (priv->exif, EXIF_TAG_PIXEL_X_DIMENSION);
+	if (entry != NULL && (priv->width >= 0)) {
+		if (entry->format == EXIF_FORMAT_LONG)
+			exif_set_long (entry->data, bo, priv->width);
+		else if (entry->format == EXIF_FORMAT_SHORT)
+			exif_set_short (entry->data, bo, priv->width);
+		else
+			g_warning ("Exif entry has unsupported size");
+	}
+
+	/* Update image height */
+	entry = exif_data_get_entry (priv->exif, EXIF_TAG_PIXEL_Y_DIMENSION);
+	if (entry != NULL && (priv->height >= 0)) {
+		if (entry->format == EXIF_FORMAT_LONG)
+			exif_set_long (entry->data, bo, priv->height);
+		else if (entry->format == EXIF_FORMAT_SHORT)
+			exif_set_short (entry->data, bo, priv->height);
+		else
+			g_warning ("Exif entry has unsupported size");
+	}
+
+	/* Update image orientation */
+	entry = exif_data_get_entry (priv->exif, EXIF_TAG_ORIENTATION);
+	if (entry != NULL) {
+		if (entry->format == EXIF_FORMAT_LONG)
+			exif_set_long (entry->data, bo, 1);
+		else if (entry->format == EXIF_FORMAT_SHORT)
+			exif_set_short (entry->data, bo, 1);
+		else
+			g_warning ("Exif entry has unsupported size");
+
+		priv->orientation = 1;
+	}
+#endif
+}
+
+static void
+eom_image_real_transform (EomImage     *img,
+			  EomTransform *trans,
+			  gboolean      is_undo,
+			  EomJob       *job)
+{
+	EomImagePrivate *priv;
+	GdkPixbuf *transformed;
+	gboolean modified = FALSE;
+
+	g_return_if_fail (EOM_IS_IMAGE (img));
+	g_return_if_fail (EOM_IS_TRANSFORM (trans));
+
+	priv = img->priv;
+
+	if (priv->image != NULL) {
+		transformed = eom_transform_apply (trans, priv->image, job);
+
+		g_object_unref (priv->image);
+		priv->image = transformed;
+
+		priv->width = gdk_pixbuf_get_width (transformed);
+		priv->height = gdk_pixbuf_get_height (transformed);
+
+		modified = TRUE;
+	}
+
+	if (priv->thumbnail != NULL) {
+		transformed = eom_transform_apply (trans, priv->thumbnail, NULL);
+
+		g_object_unref (priv->thumbnail);
+		priv->thumbnail = transformed;
+
+		modified = TRUE;
+	}
+
+	if (modified) {
+		priv->modified = TRUE;
+		eom_image_update_exif_data (img);
+	}
+
+	if (priv->trans == NULL) {
+		g_object_ref (trans);
+		priv->trans = trans;
+	} else {
+		EomTransform *composition;
+
+		composition = eom_transform_compose (priv->trans, trans);
+
+		g_object_unref (priv->trans);
+
+		priv->trans = composition;
+	}
+
+	if (!is_undo) {
+		g_object_ref (trans);
+		priv->undo_stack = g_slist_prepend (priv->undo_stack, trans);
+	}
+}
+
+static gboolean
+do_emit_size_prepared_signal (EomImage *img)
+{
+	g_signal_emit (img, signals[SIGNAL_SIZE_PREPARED], 0,
+		       img->priv->width, img->priv->height);
+	return FALSE;
+}
+
+static void
+eom_image_emit_size_prepared (EomImage *img)
+{
+	g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+	                (GSourceFunc) do_emit_size_prepared_signal,
+	                 g_object_ref (img), g_object_unref);
+}
+
+static void
+eom_image_size_prepared (GdkPixbufLoader *loader,
+			 gint             width,
+			 gint             height,
+			 gpointer         data)
+{
+	EomImage *img;
+
+	eom_debug (DEBUG_IMAGE_LOAD);
+
+	g_return_if_fail (EOM_IS_IMAGE (data));
+
+	img = EOM_IMAGE (data);
+
+	g_mutex_lock (&img->priv->status_mutex);
+
+	img->priv->width = width;
+	img->priv->height = height;
+
+	g_mutex_unlock (&img->priv->status_mutex);
+
+#ifdef HAVE_EXIF
+	if (!img->priv->autorotate || img->priv->exif)
+#endif
+		eom_image_emit_size_prepared (img);
+}
+
+static EomMetadataReader*
+check_for_metadata_img_format (EomImage *img, guchar *buffer, guint bytes_read)
+{
+	EomMetadataReader *md_reader = NULL;
+
+	eom_debug_message (DEBUG_IMAGE_DATA, "Check image format for jpeg: %x%x - length: %i",
+			   buffer[0], buffer[1], bytes_read);
+
+	if (bytes_read >= 2) {
+		/* SOI (start of image) marker for JPEGs is 0xFFD8 */
+		if ((buffer[0] == 0xFF) && (buffer[1] == 0xD8)) {
+			md_reader = eom_metadata_reader_new (EOM_METADATA_JPEG);
+		}
+		if (bytes_read >= 8 &&
+		    memcmp (buffer, "\x89PNG\x0D\x0A\x1a\x0A", 8) == 0) {
+			md_reader = eom_metadata_reader_new (EOM_METADATA_PNG);
+		}
+	}
+
+	return md_reader;
+}
+
+static gboolean
+eom_image_needs_transformation (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+	return (img->priv->trans != NULL || img->priv->trans_autorotate != NULL);
+}
+
+static gboolean
+eom_image_apply_transformations (EomImage *img, GError **error)
+{
+	GdkPixbuf *transformed = NULL;
+	EomTransform *composition = NULL;
+	EomImagePrivate *priv;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+	priv = img->priv;
+
+	if (priv->trans == NULL && priv->trans_autorotate == NULL) {
+		return TRUE;
+	}
+
+	if (priv->image == NULL) {
+		g_set_error (error,
+			     EOM_IMAGE_ERROR,
+			     EOM_IMAGE_ERROR_NOT_LOADED,
+			     _("Transformation on unloaded image."));
+
+		return FALSE;
+	}
+
+	if (priv->trans != NULL && priv->trans_autorotate != NULL) {
+		composition = eom_transform_compose (priv->trans,
+						     priv->trans_autorotate);
+	} else if (priv->trans != NULL) {
+		composition = g_object_ref (priv->trans);
+	} else if (priv->trans_autorotate != NULL) {
+		composition = g_object_ref (priv->trans_autorotate);
+	}
+
+	if (composition != NULL) {
+		transformed = eom_transform_apply (composition, priv->image, NULL);
+	}
+
+	g_object_unref (priv->image);
+	priv->image = transformed;
+
+	if (transformed != NULL) {
+		priv->width = gdk_pixbuf_get_width (priv->image);
+		priv->height = gdk_pixbuf_get_height (priv->image);
+	} else {
+		g_set_error (error,
+			     EOM_IMAGE_ERROR,
+			     EOM_IMAGE_ERROR_GENERIC,
+			     _("Transformation failed."));
+ 	}
+
+	g_object_unref (composition);
+
+	return (transformed != NULL);
+}
+
+static void
+eom_image_get_file_info (EomImage *img,
+			 goffset *bytes,
+			 gchar **mime_type,
+			 GError **error)
+{
+	GFileInfo *file_info;
+
+	file_info = g_file_query_info (img->priv->file,
+				       G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+				       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+				       0, NULL, error);
+
+	if (file_info == NULL) {
+		if (bytes)
+			*bytes = 0;
+
+		if (mime_type)
+			*mime_type = NULL;
+
+		g_set_error (error,
+			     EOM_IMAGE_ERROR,
+			     EOM_IMAGE_ERROR_VFS,
+			     "Error in getting image file info");
+	} else {
+		if (bytes)
+			*bytes = g_file_info_get_size (file_info);
+
+		if (mime_type)
+			*mime_type = g_strdup (g_file_info_get_content_type (file_info));
+		g_object_unref (file_info);
+	}
+}
+
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+void
+eom_image_apply_display_profile (EomImage *img, cmsHPROFILE screen)
+{
+	EomImagePrivate *priv;
+	cmsHTRANSFORM transform;
+	gint row, width, rows, stride;
+	guchar *p;
+
+	g_return_if_fail (img != NULL);
+
+	priv = img->priv;
+
+	if (screen == NULL) return;
+	if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
+		return;
+	}
+
+	if (priv->profile == NULL) {
+		/* Check whether GdkPixbuf was able to extract a profile */
+		const char* data = gdk_pixbuf_get_option (priv->image,
+		                                          "icc-profile");
+
+		if(data) {
+			gsize   profile_size = 0;
+			guchar *profile_data = g_base64_decode(data,
+			                                       &profile_size);
+
+			if (profile_data && profile_size > 0) {
+				eom_debug_message (DEBUG_LCMS,
+				                   "Using ICC profile "
+				                   "extracted by GdkPixbuf");
+				priv->profile =
+					cmsOpenProfileFromMem(profile_data,
+					                      profile_size);
+				g_free(profile_data);
+			}
+		}
+
+		if(priv->profile == NULL) {
+			/* Assume sRGB color space for images without ICC profile */
+			eom_debug_message (DEBUG_LCMS, "Image has no ICC profile. "
+					   "Assuming sRGB.");
+			priv->profile = cmsCreate_sRGBProfile ();
+		}
+	}
+
+	/* TODO: support other colorspaces than RGB */
+	if (cmsGetColorSpace (priv->profile) != cmsSigRgbData ||
+	    cmsGetColorSpace (screen) != cmsSigRgbData) {
+		eom_debug_message (DEBUG_LCMS, "One or both ICC profiles not in RGB colorspace; not correcting");
+		return;
+	}
+
+	cmsUInt32Number color_type = TYPE_RGB_8;
+
+	if (gdk_pixbuf_get_has_alpha (priv->image))
+		color_type = TYPE_RGBA_8;
+
+	transform = cmsCreateTransform (priv->profile,
+	                                color_type,
+	                                screen,
+	                                color_type,
+	                                INTENT_PERCEPTUAL,
+	                                0);
+
+	if (G_LIKELY (transform != NULL)) {
+		rows = gdk_pixbuf_get_height (priv->image);
+		width = gdk_pixbuf_get_width (priv->image);
+		stride = gdk_pixbuf_get_rowstride (priv->image);
+		p = gdk_pixbuf_get_pixels (priv->image);
+
+		for (row = 0; row < rows; ++row) {
+			cmsDoTransform (transform, p, p, width);
+			p += stride;
+		}
+		cmsDeleteTransform (transform);
+	}
+}
+
+static void
+eom_image_set_icc_data (EomImage *img, EomMetadataReader *md_reader)
+{
+	EomImagePrivate *priv = img->priv;
+
+	priv->profile = eom_metadata_reader_get_icc_profile (md_reader);
+
+
+}
+#endif
+
+static void
+eom_image_set_orientation (EomImage *img)
+{
+	EomImagePrivate *priv;
+#ifdef HAVE_EXIF
+	ExifData* exif;
+#endif
+
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	priv = img->priv;
+
+#ifdef HAVE_EXIF
+	exif = (ExifData*) eom_image_get_exif_info (img);
+
+	if (exif != NULL) {
+		ExifByteOrder o = exif_data_get_byte_order (exif);
+
+		ExifEntry *entry = exif_data_get_entry (exif,
+							EXIF_TAG_ORIENTATION);
+
+		if (entry && entry->data != NULL) {
+			priv->orientation = exif_get_short (entry->data, o);
+		}
+		exif_data_unref (exif);
+	} else
+#endif
+	{
+		GdkPixbuf *pbuf;
+
+		pbuf = eom_image_get_pixbuf (img);
+
+		if (pbuf) {
+			const gchar *o_str;
+
+			o_str = gdk_pixbuf_get_option (pbuf, "orientation");
+			if (o_str) {
+				short t = (short) g_ascii_strtoll (o_str,
+								   NULL, 10);
+				if (t >= 0 && t < 9)
+					priv->orientation = t;
+			}
+			g_object_unref (pbuf);
+		}
+	}
+
+	if (priv->orientation > 4 &&
+	    priv->orientation < 9) {
+		gint tmp;
+
+		tmp = priv->width;
+		priv->width = priv->height;
+		priv->height = tmp;
+	}
+}
+
+static void
+eom_image_real_autorotate (EomImage *img)
+{
+	static const EomTransformType lookup[8] = {EOM_TRANSFORM_NONE,
+					     EOM_TRANSFORM_FLIP_HORIZONTAL,
+					     EOM_TRANSFORM_ROT_180,
+					     EOM_TRANSFORM_FLIP_VERTICAL,
+					     EOM_TRANSFORM_TRANSPOSE,
+					     EOM_TRANSFORM_ROT_90,
+					     EOM_TRANSFORM_TRANSVERSE,
+					     EOM_TRANSFORM_ROT_270};
+	EomImagePrivate *priv;
+	EomTransformType type;
+
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	priv = img->priv;
+
+	type = (priv->orientation >= 1 && priv->orientation <= 8 ?
+		lookup[priv->orientation - 1] : EOM_TRANSFORM_NONE);
+
+	if (type != EOM_TRANSFORM_NONE) {
+		img->priv->trans_autorotate = eom_transform_new (type);
+	}
+
+	/* Disable auto orientation for next loads */
+	priv->autorotate = FALSE;
+}
+
+void
+eom_image_autorotate (EomImage *img)
+{
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	/* Schedule auto orientation */
+	img->priv->autorotate = TRUE;
+}
+
+#ifdef HAVE_EXEMPI
+static void
+eom_image_set_xmp_data (EomImage *img, EomMetadataReader *md_reader)
+{
+	EomImagePrivate *priv;
+
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	priv = img->priv;
+
+	if (priv->xmp) {
+		xmp_free (priv->xmp);
+	}
+	priv->xmp = eom_metadata_reader_get_xmp_data (md_reader);
+}
+#endif
+
+static void
+eom_image_set_exif_data (EomImage *img, EomMetadataReader *md_reader)
+{
+	EomImagePrivate *priv;
+
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	priv = img->priv;
+
+#ifdef HAVE_EXIF
+	g_mutex_lock (&priv->status_mutex);
+	if (priv->exif) {
+		exif_data_unref (priv->exif);
+	}
+	priv->exif = eom_metadata_reader_get_exif_data (md_reader);
+	g_mutex_unlock (&priv->status_mutex);
+
+	priv->exif_chunk = NULL;
+	priv->exif_chunk_len = 0;
+
+	/* EXIF data is already available, set the image orientation */
+	if (priv->autorotate) {
+		eom_image_set_orientation (img);
+
+		/* Emit size prepared signal if we have the size */
+		if (priv->width > 0 &&
+		    priv->height > 0) {
+			eom_image_emit_size_prepared (img);
+		}
+	}
+#else
+	if (priv->exif_chunk) {
+		g_free (priv->exif_chunk);
+	}
+	eom_metadata_reader_get_exif_chunk (md_reader,
+					    &priv->exif_chunk,
+					    &priv->exif_chunk_len);
+#endif
+}
+
+/*
+ * Attempts to get the image dimensions from the thumbnail.
+ * Returns FALSE if this information is not found.
+ **/
+static gboolean
+eom_image_get_dimension_from_thumbnail (EomImage *image,
+			                gint     *width,
+			                gint     *height)
+{
+	if (image->priv->thumbnail == NULL)
+		return FALSE;
+
+	*width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (image->priv->thumbnail),
+						     EOM_THUMBNAIL_ORIGINAL_WIDTH));
+	*height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (image->priv->thumbnail),
+						      EOM_THUMBNAIL_ORIGINAL_HEIGHT));
+
+	return (*width || *height);
+}
+
+static gboolean
+eom_image_real_load (EomImage *img,
+		     guint     data2read,
+		     EomJob   *job,
+		     GError  **error)
+{
+	EomImagePrivate *priv;
+	GFileInputStream *input_stream;
+	EomMetadataReader *md_reader = NULL;
+	GdkPixbufFormat *format;
+	gchar *mime_type;
+	GdkPixbufLoader *loader = NULL;
+	guchar *buffer;
+	goffset bytes_read, bytes_read_total = 0;
+	gboolean failed = FALSE;
+	gboolean first_run = TRUE;
+	gboolean set_metadata = TRUE;
+        gboolean use_rsvg = FALSE;
+	gboolean read_image_data = (data2read & EOM_IMAGE_DATA_IMAGE);
+	gboolean read_only_dimension = (data2read & EOM_IMAGE_DATA_DIMENSION) &&
+				  ((data2read ^ EOM_IMAGE_DATA_DIMENSION) == 0);
+
+
+	priv = img->priv;
+
+ 	g_assert (!read_image_data || priv->image == NULL);
+
+	if (read_image_data && priv->file_type != NULL) {
+		g_free (priv->file_type);
+		priv->file_type = NULL;
+	}
+
+	eom_image_get_file_info (img, &priv->bytes, &mime_type, error);
+
+	if (error && *error) {
+		g_free (mime_type);
+		return FALSE;
+	}
+
+	if (read_only_dimension) {
+		gint width, height;
+		gboolean done;
+
+		done = eom_image_get_dimension_from_thumbnail (img,
+							       &width,
+							       &height);
+
+		if (done) {
+			priv->width = width;
+			priv->height = height;
+
+			g_free (mime_type);
+			return TRUE;
+		}
+	}
+
+	input_stream = g_file_read (priv->file, NULL, error);
+
+	if (input_stream == NULL) {
+		g_free (mime_type);
+
+		if (error != NULL) {
+			g_clear_error (error);
+			g_set_error (error,
+				     EOM_IMAGE_ERROR,
+				     EOM_IMAGE_ERROR_VFS,
+				     "Failed to open input stream for file");
+		}
+		return FALSE;
+	}
+
+	buffer = g_new0 (guchar, EOM_IMAGE_READ_BUFFER_SIZE);
+
+	if (read_image_data || read_only_dimension) {
+#ifdef HAVE_RSVG
+		if (priv->svg != NULL) {
+			g_object_unref (priv->svg);
+			priv->svg = NULL;
+		}
+
+		if (!strcmp (mime_type, "image/svg+xml")
+#if LIBRSVG_CHECK_FEATURE(SVGZ)
+                    || !strcmp (mime_type, "image/svg+xml-compressed")
+#endif
+                ) {
+			gchar *file_path;
+			/* Keep the object for rendering */
+			priv->svg = rsvg_handle_new ();
+                        use_rsvg = (priv->svg != NULL);
+			file_path = g_file_get_path (priv->file);
+			rsvg_handle_set_base_uri (priv->svg, file_path);
+			g_free (file_path);
+		}
+#endif
+
+                if (!use_rsvg) {
+		        loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, error);
+
+		        if (error && *error) {
+			        g_error_free (*error);
+			        *error = NULL;
+
+			        loader = gdk_pixbuf_loader_new ();
+		        }
+
+		        g_signal_connect_object (G_OBJECT (loader),
+					         "size-prepared",
+					         G_CALLBACK (eom_image_size_prepared),
+					         img,
+					         0);
+                 }
+	}
+	g_free (mime_type);
+
+	while (!priv->cancel_loading) {
+		/* FIXME: make this async */
+		bytes_read = g_input_stream_read (G_INPUT_STREAM (input_stream),
+						  buffer,
+						  EOM_IMAGE_READ_BUFFER_SIZE,
+						  NULL, error);
+
+		if (bytes_read == 0) {
+			/* End of the file */
+			break;
+		} else if (bytes_read == -1) {
+			failed = TRUE;
+
+			g_set_error (error,
+				     EOM_IMAGE_ERROR,
+				     EOM_IMAGE_ERROR_VFS,
+				     "Failed to read from input stream");
+
+			break;
+		}
+
+		if ((read_image_data || read_only_dimension)) {
+#ifdef HAVE_RSVG
+			if (use_rsvg) {
+                            gboolean res;
+
+			    res = rsvg_handle_write (priv->svg, buffer,
+                                                     bytes_read, error);
+
+                            if (G_UNLIKELY (!res)) {
+				failed = TRUE;
+				break;
+                            }
+			} else
+#endif
+			if (!gdk_pixbuf_loader_write (loader, buffer, bytes_read, error)) {
+				failed = TRUE;
+				break;
+			}
+		}
+
+		bytes_read_total += bytes_read;
+
+		if (job != NULL) {
+			float progress = (float) bytes_read_total / (float) priv->bytes;
+			eom_job_set_progress (job, progress);
+		}
+
+		if (first_run) {
+			md_reader = check_for_metadata_img_format (img, buffer, bytes_read);
+
+			if (md_reader == NULL) {
+				if (data2read == EOM_IMAGE_DATA_EXIF) {
+					g_set_error (error,
+						     EOM_IMAGE_ERROR,
+						     EOM_IMAGE_ERROR_GENERIC,
+						     _("EXIF not supported for this file format."));
+					break;
+				}
+
+				priv->metadata_status = EOM_IMAGE_METADATA_NOT_AVAILABLE;
+			}
+
+			first_run = FALSE;
+		}
+
+		if (md_reader != NULL) {
+			eom_metadata_reader_consume (md_reader, buffer, bytes_read);
+
+			if (eom_metadata_reader_finished (md_reader)) {
+				if (set_metadata) {
+					eom_image_set_exif_data (img, md_reader);
+
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+					eom_image_set_icc_data (img, md_reader);
+#endif
+
+#ifdef HAVE_EXEMPI
+					eom_image_set_xmp_data (img, md_reader);
+#endif
+					set_metadata = FALSE;
+					priv->metadata_status = EOM_IMAGE_METADATA_READY;
+				}
+
+				if (data2read == EOM_IMAGE_DATA_EXIF)
+					break;
+			}
+		}
+
+		if (read_only_dimension &&
+		    eom_image_has_data (img, EOM_IMAGE_DATA_DIMENSION)) {
+			break;
+		}
+	}
+
+	if (read_image_data || read_only_dimension) {
+#ifdef HAVE_RSVG
+		if (use_rsvg) {
+			/* Ignore the error if loading failed earlier
+			 * as the error will already be set in that case */
+			rsvg_handle_close (priv->svg,
+			                   (failed ? NULL : error));
+                } else
+#endif
+		if (failed) {
+			gdk_pixbuf_loader_close (loader, NULL);
+		} else if (!gdk_pixbuf_loader_close (loader, error)) {
+			if (gdk_pixbuf_loader_get_pixbuf (loader) != NULL) {
+				/* Clear error in order to support partial
+				 * images as well. */
+				g_clear_error (error);
+			}
+		}
+	}
+
+	g_free (buffer);
+
+	g_object_unref (G_OBJECT (input_stream));
+
+	failed = (failed ||
+		  priv->cancel_loading ||
+		  bytes_read_total == 0 ||
+		  (error && *error != NULL));
+
+	if (failed) {
+		if (priv->cancel_loading) {
+			priv->cancel_loading = FALSE;
+			priv->status = EOM_IMAGE_STATUS_UNKNOWN;
+		} else {
+			priv->status = EOM_IMAGE_STATUS_FAILED;
+		}
+	} else if (read_image_data) {
+		if (priv->image != NULL) {
+			g_object_unref (priv->image);
+		}
+
+#ifdef HAVE_RSVG
+                if (use_rsvg) {
+                    priv->image = rsvg_handle_get_pixbuf (priv->svg);
+                } else
+#endif
+
+                {
+
+		priv->anim = gdk_pixbuf_loader_get_animation (loader);
+
+		if (gdk_pixbuf_animation_is_static_image (priv->anim)) {
+			priv->image = gdk_pixbuf_animation_get_static_image (priv->anim);
+			priv->anim = NULL;
+		} else {
+			priv->anim_iter = gdk_pixbuf_animation_get_iter (priv->anim,NULL);
+			priv->image = gdk_pixbuf_animation_iter_get_pixbuf (priv->anim_iter);
+		}
+
+                }
+
+		if (G_LIKELY (priv->image != NULL)) {
+                        if (!use_rsvg)
+			        g_object_ref (priv->image);
+
+			priv->width = gdk_pixbuf_get_width (priv->image);
+			priv->height = gdk_pixbuf_get_height (priv->image);
+
+                        if (use_rsvg) {
+                                format = NULL;
+                                priv->file_type = g_strdup ("svg");
+                        } else {
+			        format = gdk_pixbuf_loader_get_format (loader);
+                        }
+
+			if (format != NULL) {
+				priv->file_type = gdk_pixbuf_format_get_name (format);
+			}
+
+			priv->file_is_changed = FALSE;
+
+			/* Set orientation again for safety, eg. if we don't
+			 * have Exif data or HAVE_EXIF is undefined. */
+			if (priv->autorotate) {
+				eom_image_set_orientation (img);
+				eom_image_emit_size_prepared (img);
+			}
+
+		} else {
+			/* Some loaders don't report errors correctly.
+			 * Error will be set below. */
+			failed = TRUE;
+			priv->status = EOM_IMAGE_STATUS_FAILED;
+		}
+	}
+
+	if (loader != NULL) {
+		g_object_unref (loader);
+	}
+
+	if (md_reader != NULL) {
+		g_object_unref (md_reader);
+		md_reader = NULL;
+	}
+
+	/* Catch-all in case of poor-error reporting */
+	if (failed && error && *error == NULL) {
+		g_set_error (error,
+			     EOM_IMAGE_ERROR,
+			     EOM_IMAGE_ERROR_GENERIC,
+			     _("Image loading failed."));
+	}
+
+	return !failed;
+}
+
+gboolean
+eom_image_has_data (EomImage *img, EomImageData req_data)
+{
+	EomImagePrivate *priv;
+	gboolean has_data = TRUE;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+	priv = img->priv;
+
+	if ((req_data & EOM_IMAGE_DATA_IMAGE) > 0) {
+		req_data = (req_data & ~EOM_IMAGE_DATA_IMAGE);
+		has_data = has_data && (priv->image != NULL);
+	}
+
+	if ((req_data & EOM_IMAGE_DATA_DIMENSION) > 0 ) {
+		req_data = (req_data & ~EOM_IMAGE_DATA_DIMENSION);
+		has_data = has_data && (priv->width >= 0) && (priv->height >= 0);
+	}
+
+	if ((req_data & EOM_IMAGE_DATA_EXIF) > 0) {
+		req_data = (req_data & ~EOM_IMAGE_DATA_EXIF);
+#ifdef HAVE_EXIF
+		has_data = has_data && (priv->exif != NULL);
+#else
+		has_data = has_data && (priv->exif_chunk != NULL);
+#endif
+	}
+
+	if ((req_data & EOM_IMAGE_DATA_XMP) > 0) {
+		req_data = (req_data & ~EOM_IMAGE_DATA_XMP);
+#ifdef HAVE_EXEMPI
+		has_data = has_data && (priv->xmp != NULL);
+#endif
+	}
+
+	if (req_data != 0) {
+		g_warning ("Asking for unknown data, remaining: %i\n", req_data);
+		has_data = FALSE;
+	}
+
+	return has_data;
+}
+
+gboolean
+eom_image_load (EomImage *img, EomImageData data2read, EomJob *job, GError **error)
+{
+	EomImagePrivate *priv;
+	gboolean success = FALSE;
+
+	eom_debug (DEBUG_IMAGE_LOAD);
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+	priv = EOM_IMAGE (img)->priv;
+
+	if (data2read == 0) {
+		return TRUE;
+	}
+
+	if (eom_image_has_data (img, data2read)) {
+		return TRUE;
+	}
+
+	priv->status = EOM_IMAGE_STATUS_LOADING;
+
+	success = eom_image_real_load (img, data2read, job, error);
+
+	/* Check that the metadata was loaded at least once before
+	 * trying to autorotate. Also only an imatge load job should try to
+	 * autorotate and image */
+	if (priv->autorotate &&
+#ifdef HAVE_EXIF
+	    priv->metadata_status != EOM_IMAGE_METADATA_NOT_READ &&
+#endif
+	    data2read & EOM_IMAGE_DATA_IMAGE) {
+	                          eom_image_real_autorotate (img);
+	}
+
+	if (success && eom_image_needs_transformation (img)) {
+		success = eom_image_apply_transformations (img, error);
+	}
+
+	if (success) {
+		priv->status = EOM_IMAGE_STATUS_LOADED;
+	} else {
+		priv->status = EOM_IMAGE_STATUS_FAILED;
+	}
+
+	return success;
+}
+
+void
+eom_image_set_thumbnail (EomImage *img, GdkPixbuf *thumbnail)
+{
+	EomImagePrivate *priv;
+
+	g_return_if_fail (EOM_IS_IMAGE (img));
+	g_return_if_fail (GDK_IS_PIXBUF (thumbnail) || thumbnail == NULL);
+
+	priv = img->priv;
+
+	if (priv->thumbnail != NULL) {
+		g_object_unref (priv->thumbnail);
+		priv->thumbnail = NULL;
+	}
+
+	if (thumbnail != NULL && priv->trans != NULL) {
+		priv->thumbnail = eom_transform_apply (priv->trans, thumbnail, NULL);
+	} else {
+		priv->thumbnail = thumbnail;
+
+		if (thumbnail != NULL) {
+			g_object_ref (priv->thumbnail);
+		}
+	}
+
+	if (priv->thumbnail != NULL) {
+		g_signal_emit (img, signals[SIGNAL_THUMBNAIL_CHANGED], 0);
+	}
+}
+
+/**
+ * eom_image_get_pixbuf:
+ * @img: a #EomImage
+ *
+ * Gets the #GdkPixbuf of the image
+ *
+ * Returns: (transfer full): a #GdkPixbuf
+ **/
+GdkPixbuf *
+eom_image_get_pixbuf (EomImage *img)
+{
+	GdkPixbuf *image = NULL;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	g_mutex_lock (&img->priv->status_mutex);
+	image = img->priv->image;
+	g_mutex_unlock (&img->priv->status_mutex);
+
+	if (image != NULL) {
+		g_object_ref (image);
+	}
+
+	return image;
+}
+
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+cmsHPROFILE
+eom_image_get_profile (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	return img->priv->profile;
+}
+#endif
+
+/**
+ * eom_image_get_thumbnail:
+ * @img: a #EomImage
+ *
+ * Gets the thumbnail pixbuf for @img
+ *
+ * Returns: (transfer full): a #GdkPixbuf with a thumbnail
+ **/
+GdkPixbuf *
+eom_image_get_thumbnail (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	if (img->priv->thumbnail != NULL) {
+		return g_object_ref (img->priv->thumbnail);
+	}
+
+	return NULL;
+}
+
+void
+eom_image_get_size (EomImage *img, int *width, int *height)
+{
+	EomImagePrivate *priv;
+
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	priv = img->priv;
+
+	*width = priv->width;
+	*height = priv->height;
+}
+
+void
+eom_image_transform (EomImage *img, EomTransform *trans, EomJob *job)
+{
+	eom_image_real_transform (img, trans, FALSE, job);
+}
+
+void
+eom_image_undo (EomImage *img)
+{
+	EomImagePrivate *priv;
+	EomTransform *trans;
+	EomTransform *inverse;
+
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	priv = img->priv;
+
+	if (priv->undo_stack != NULL) {
+		trans = EOM_TRANSFORM (priv->undo_stack->data);
+
+		inverse = eom_transform_reverse (trans);
+
+		eom_image_real_transform (img, inverse, TRUE, NULL);
+
+		priv->undo_stack = g_slist_delete_link (priv->undo_stack, priv->undo_stack);
+
+		g_object_unref (trans);
+		g_object_unref (inverse);
+
+		if (eom_transform_is_identity (priv->trans)) {
+			g_object_unref (priv->trans);
+			priv->trans = NULL;
+		}
+	}
+
+	priv->modified = (priv->undo_stack != NULL);
+}
+
+static GFile *
+tmp_file_get (void)
+{
+	GFile *tmp_file;
+	char *tmp_file_path;
+	gint fd;
+
+	tmp_file_path = g_build_filename (g_get_tmp_dir (), "eom-save-XXXXXX", NULL);
+	fd = g_mkstemp (tmp_file_path);
+	if (fd == -1) {
+		g_free (tmp_file_path);
+		return NULL;
+	}
+	else {
+		tmp_file = g_file_new_for_path (tmp_file_path);
+		g_free (tmp_file_path);
+		return tmp_file;
+	}
+}
+
+static void
+transfer_progress_cb (goffset cur_bytes,
+		      goffset total_bytes,
+		      gpointer user_data)
+{
+	EomImage *image = EOM_IMAGE (user_data);
+
+	if (cur_bytes > 0) {
+		g_signal_emit (G_OBJECT(image),
+			       signals[SIGNAL_SAVE_PROGRESS],
+			       0,
+			       (gfloat) cur_bytes / (gfloat) total_bytes);
+	}
+}
+
+static void
+tmp_file_restore_unix_attributes (GFile *temp_file,
+				  GFile *target_file)
+{
+	GFileInfo *file_info;
+	guint      uid;
+	guint      gid;
+	guint      mode;
+	guint      mode_mask = 00600;
+
+	GError    *error = NULL;
+
+	g_return_if_fail (G_IS_FILE (temp_file));
+	g_return_if_fail (G_IS_FILE (target_file));
+
+	/* check if file exists */
+	if (!g_file_query_exists (target_file, NULL)) {
+		eom_debug_message (DEBUG_IMAGE_SAVE,
+				   "Target file doesn't exist. Setting default attributes.");
+		return;
+	}
+
+	/* retrieve UID, GID, and MODE of the original file info */
+	file_info = g_file_query_info (target_file,
+				       "unix::uid,unix::gid,unix::mode",
+				       G_FILE_QUERY_INFO_NONE,
+				       NULL,
+				       &error);
+
+	/* check that there aren't any error */
+	if (error != NULL) {
+		eom_debug_message (DEBUG_IMAGE_SAVE,
+				   "File information not available. Setting default attributes.");
+
+		/* free objects */
+		g_object_unref (file_info);
+		g_clear_error (&error);
+
+		return;
+	}
+
+	/* save UID, GID and MODE values */
+	uid = g_file_info_get_attribute_uint32 (file_info,
+						G_FILE_ATTRIBUTE_UNIX_UID);
+
+	gid = g_file_info_get_attribute_uint32 (file_info,
+						G_FILE_ATTRIBUTE_UNIX_GID);
+
+	mode = g_file_info_get_attribute_uint32 (file_info,
+						 G_FILE_ATTRIBUTE_UNIX_MODE);
+
+	/* apply default mode mask to file mode */
+	mode |= mode_mask;
+
+	/* restore original UID, GID, and MODE into the temporal file */
+	g_file_set_attribute_uint32 (temp_file,
+				     G_FILE_ATTRIBUTE_UNIX_UID,
+				     uid,
+				     G_FILE_QUERY_INFO_NONE,
+				     NULL,
+				     &error);
+
+	/* check that there aren't any error */
+	if (error != NULL) {
+		eom_debug_message (DEBUG_IMAGE_SAVE,
+				   "You do not have the permissions necessary to change the file UID.");
+
+		g_clear_error (&error);
+	}
+
+	g_file_set_attribute_uint32 (temp_file,
+				     G_FILE_ATTRIBUTE_UNIX_GID,
+				     gid,
+				     G_FILE_QUERY_INFO_NONE,
+				     NULL,
+				     &error);
+
+	/* check that there aren't any error */
+	if (error != NULL) {
+		eom_debug_message (DEBUG_IMAGE_SAVE,
+				   "You do not have the permissions necessary to change the file GID. Setting user default GID.");
+
+		g_clear_error (&error);
+	}
+
+	g_file_set_attribute_uint32 (temp_file,
+				     G_FILE_ATTRIBUTE_UNIX_MODE,
+				     mode,
+				     G_FILE_QUERY_INFO_NONE,
+				     NULL,
+				     &error);
+
+	/* check that there aren't any error */
+	if (error != NULL) {
+		eom_debug_message (DEBUG_IMAGE_SAVE,
+				   "You do not have the permissions necessary to change the file MODE.");
+
+		g_clear_error (&error);
+	}
+
+	/* free objects */
+	g_object_unref (file_info);
+}
+
+static gboolean
+tmp_file_move_to_uri (EomImage *image,
+		      GFile *tmpfile,
+		      GFile *file,
+		      gboolean overwrite,
+		      GError **error)
+{
+	gboolean result;
+	GError *ioerror = NULL;
+
+	/* try to restore target file unix attributes */
+	tmp_file_restore_unix_attributes (tmpfile, file);
+
+	/* replace target file with temporal file */
+	result = g_file_move (tmpfile,
+			      file,
+			      (overwrite ? G_FILE_COPY_OVERWRITE : 0) |
+			      G_FILE_COPY_ALL_METADATA,
+			      NULL,
+			      (GFileProgressCallback) transfer_progress_cb,
+			      image,
+			      &ioerror);
+
+	if (result == FALSE) {
+		if (g_error_matches (ioerror, G_IO_ERROR,
+				     G_IO_ERROR_EXISTS)) {
+			g_set_error (error, EOM_IMAGE_ERROR,
+				     EOM_IMAGE_ERROR_FILE_EXISTS,
+				     "File exists");
+		} else {
+			g_set_error (error, EOM_IMAGE_ERROR,
+				     EOM_IMAGE_ERROR_VFS,
+				     "VFS error moving the temp file");
+		}
+		g_clear_error (&ioerror);
+	}
+
+	return result;
+}
+
+static gboolean
+tmp_file_delete (GFile *tmpfile)
+{
+	gboolean result;
+	GError *err = NULL;
+
+	if (tmpfile == NULL) return FALSE;
+
+	result = g_file_delete (tmpfile, NULL, &err);
+	if (result == FALSE) {
+		char *tmpfile_path;
+		if (err != NULL) {
+			if (err->code == G_IO_ERROR_NOT_FOUND) {
+				g_error_free (err);
+				return TRUE;
+			}
+			g_error_free (err);
+		}
+		tmpfile_path = g_file_get_path (tmpfile);
+		g_warning ("Couldn't delete temporary file: %s", tmpfile_path);
+		g_free (tmpfile_path);
+	}
+
+	return result;
+}
+
+static void
+eom_image_reset_modifications (EomImage *image)
+{
+	EomImagePrivate *priv;
+
+	g_return_if_fail (EOM_IS_IMAGE (image));
+
+	priv = image->priv;
+
+	g_slist_free_full (priv->undo_stack, g_object_unref);
+	priv->undo_stack = NULL;
+
+	if (priv->trans != NULL) {
+		g_object_unref (priv->trans);
+		priv->trans = NULL;
+	}
+
+	if (priv->trans_autorotate != NULL) {
+		g_object_unref (priv->trans_autorotate);
+		priv->trans_autorotate = NULL;
+	}
+
+	priv->modified = FALSE;
+}
+
+static void
+eom_image_link_with_target (EomImage *image, EomImageSaveInfo *target)
+{
+	EomImagePrivate *priv;
+
+	g_return_if_fail (EOM_IS_IMAGE (image));
+	g_return_if_fail (EOM_IS_IMAGE_SAVE_INFO (target));
+
+	priv = image->priv;
+
+	/* update file location */
+	if (priv->file != NULL) {
+		g_object_unref (priv->file);
+	}
+	priv->file = g_object_ref (target->file);
+
+	/* Clear caption and caption key, these will be
+	 * updated on next eom_image_get_caption call.
+	 */
+	if (priv->caption != NULL) {
+		g_free (priv->caption);
+		priv->caption = NULL;
+	}
+	if (priv->collate_key != NULL) {
+		g_free (priv->collate_key);
+		priv->collate_key = NULL;
+	}
+
+	/* update file format */
+	if (priv->file_type != NULL) {
+		g_free (priv->file_type);
+	}
+	priv->file_type = g_strdup (target->format);
+}
+
+gboolean
+eom_image_save_by_info (EomImage *img, EomImageSaveInfo *source, GError **error)
+{
+	EomImagePrivate *priv;
+	EomImageStatus prev_status;
+	gboolean success = FALSE;
+	GFile *tmp_file;
+	char *tmp_file_path;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+	g_return_val_if_fail (EOM_IS_IMAGE_SAVE_INFO (source), FALSE);
+
+	priv = img->priv;
+
+	prev_status = priv->status;
+
+	/* Image is now being saved */
+	priv->status = EOM_IMAGE_STATUS_SAVING;
+
+	/* see if we need any saving at all */
+	if (source->exists && !source->modified) {
+		return TRUE;
+	}
+
+	/* fail if there is no image to save */
+	if (priv->image == NULL) {
+		g_set_error (error, EOM_IMAGE_ERROR,
+			     EOM_IMAGE_ERROR_NOT_LOADED,
+			     _("No image loaded."));
+		return FALSE;
+	}
+
+	/* generate temporary file */
+	tmp_file = tmp_file_get ();
+
+	if (tmp_file == NULL) {
+		g_set_error (error, EOM_IMAGE_ERROR,
+			     EOM_IMAGE_ERROR_TMP_FILE_FAILED,
+			     _("Temporary file creation failed."));
+		return FALSE;
+	}
+
+	tmp_file_path = g_file_get_path (tmp_file);
+
+#ifdef HAVE_JPEG
+	/* determine kind of saving */
+	if ((g_ascii_strcasecmp (source->format, EOM_FILE_FORMAT_JPEG) == 0) &&
+	    source->exists && source->modified)
+	{
+		success = eom_image_jpeg_save_file (img, tmp_file_path, source, NULL, error);
+	}
+#endif
+
+	if (!success && (*error == NULL)) {
+		success = gdk_pixbuf_save (priv->image, tmp_file_path, source->format, error, NULL);
+	}
+
+	if (success) {
+		/* try to move result file to target uri */
+		success = tmp_file_move_to_uri (img, tmp_file, priv->file, TRUE /*overwrite*/, error);
+	}
+
+	if (success) {
+		eom_image_reset_modifications (img);
+	}
+
+	tmp_file_delete (tmp_file);
+
+	g_free (tmp_file_path);
+	g_object_unref (tmp_file);
+
+	priv->status = prev_status;
+
+	return success;
+}
+
+static gboolean
+eom_image_copy_file (EomImage *image, EomImageSaveInfo *source, EomImageSaveInfo *target, GError **error)
+{
+	gboolean result;
+	GError *ioerror = NULL;
+
+	g_return_val_if_fail (EOM_IS_IMAGE_SAVE_INFO (source), FALSE);
+	g_return_val_if_fail (EOM_IS_IMAGE_SAVE_INFO (target), FALSE);
+
+	result = g_file_copy (source->file,
+			      target->file,
+			      (target->overwrite ? G_FILE_COPY_OVERWRITE : 0) |
+			      G_FILE_COPY_ALL_METADATA,
+			      NULL,
+			      EOM_IS_IMAGE (image) ? transfer_progress_cb :NULL,
+			      image,
+			      &ioerror);
+
+	if (result == FALSE) {
+		if (ioerror->code == G_IO_ERROR_EXISTS) {
+			g_set_error (error, EOM_IMAGE_ERROR,
+				     EOM_IMAGE_ERROR_FILE_EXISTS,
+				     "%s", ioerror->message);
+		} else {
+		g_set_error (error, EOM_IMAGE_ERROR,
+			     EOM_IMAGE_ERROR_VFS,
+			     "%s", ioerror->message);
+		}
+		g_error_free (ioerror);
+	}
+
+	return result;
+}
+
+gboolean
+eom_image_save_as_by_info (EomImage *img, EomImageSaveInfo *source, EomImageSaveInfo *target, GError **error)
+{
+	EomImagePrivate *priv;
+	gboolean success = FALSE;
+	char *tmp_file_path;
+	GFile *tmp_file;
+	gboolean direct_copy = FALSE;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+	g_return_val_if_fail (EOM_IS_IMAGE_SAVE_INFO (source), FALSE);
+	g_return_val_if_fail (EOM_IS_IMAGE_SAVE_INFO (target), FALSE);
+
+	priv = img->priv;
+
+	/* fail if there is no image to save */
+	if (priv->image == NULL) {
+		g_set_error (error,
+			     EOM_IMAGE_ERROR,
+			     EOM_IMAGE_ERROR_NOT_LOADED,
+			     _("No image loaded."));
+
+		return FALSE;
+	}
+
+	/* generate temporary file name */
+	tmp_file = tmp_file_get ();
+
+	if (tmp_file == NULL) {
+		g_set_error (error,
+			     EOM_IMAGE_ERROR,
+			     EOM_IMAGE_ERROR_TMP_FILE_FAILED,
+			     _("Temporary file creation failed."));
+
+		return FALSE;
+	}
+	tmp_file_path = g_file_get_path (tmp_file);
+
+	/* determine kind of saving */
+	if (g_ascii_strcasecmp (source->format, target->format) == 0 && !source->modified) {
+		success = eom_image_copy_file (img, source, target, error);
+		direct_copy = success;
+	}
+
+#ifdef HAVE_JPEG
+	else if ((g_ascii_strcasecmp (source->format, EOM_FILE_FORMAT_JPEG) == 0 && source->exists) ||
+		 (g_ascii_strcasecmp (target->format, EOM_FILE_FORMAT_JPEG) == 0))
+	{
+		success = eom_image_jpeg_save_file (img, tmp_file_path, source, target, error);
+	}
+#endif
+
+	if (!success && (*error == NULL)) {
+		success = gdk_pixbuf_save (priv->image, tmp_file_path, target->format, error, NULL);
+	}
+
+	if (success && !direct_copy) { /* not required if we alredy copied the file directly */
+		/* try to move result file to target uri */
+		success = tmp_file_move_to_uri (img, tmp_file, target->file, target->overwrite, error);
+	}
+
+	if (success) {
+		/* update image information to new uri */
+		eom_image_reset_modifications (img);
+		eom_image_link_with_target (img, target);
+	}
+
+	tmp_file_delete (tmp_file);
+	g_object_unref (tmp_file);
+	g_free (tmp_file_path);
+
+	priv->status = EOM_IMAGE_STATUS_UNKNOWN;
+
+	return success;
+}
+
+
+/*
+ * This function is extracted from
+ * File: caja/libcaja-private/caja-file.c
+ * Revision: 1.309
+ * Author: Darin Adler <darin@bentspoon.com>
+ */
+static gboolean
+have_broken_filenames (void)
+{
+	static gboolean initialized = FALSE;
+	static gboolean broken;
+
+	if (initialized) {
+		return broken;
+	}
+
+	broken = g_getenv ("G_BROKEN_FILENAMES") != NULL;
+
+	initialized = TRUE;
+
+	return broken;
+}
+
+/*
+ * This function is inspired by
+ * caja/libcaja-private/caja-file.c:caja_file_get_display_name_nocopy
+ * Revision: 1.309
+ * Author: Darin Adler <darin@bentspoon.com>
+ */
+const gchar*
+eom_image_get_caption (EomImage *img)
+{
+	EomImagePrivate *priv;
+	char *name;
+	char *utf8_name;
+	char *scheme;
+	gboolean validated = FALSE;
+	gboolean broken_filenames;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	priv = img->priv;
+
+	if (priv->file == NULL) return NULL;
+
+	if (priv->caption != NULL)
+		/* Use cached caption string */
+		return priv->caption;
+
+	name = g_file_get_basename (priv->file);
+	scheme = g_file_get_uri_scheme (priv->file);
+
+	if (name != NULL && g_ascii_strcasecmp (scheme, "file") == 0) {
+		/* Support the G_BROKEN_FILENAMES feature of
+		 * glib by using g_filename_to_utf8 to convert
+		 * local filenames to UTF-8. Also do the same
+		 * thing with any local filename that does not
+		 * validate as good UTF-8.
+		 */
+		broken_filenames = have_broken_filenames ();
+
+		if (broken_filenames || !g_utf8_validate (name, -1, NULL)) {<--- Assuming that condition 'broken_filenames' is not redundant
+			utf8_name = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
+			if (utf8_name != NULL) {
+				g_free (name);
+				name = utf8_name;
+				/* Guaranteed to be correct utf8 here */
+				validated = TRUE;
+			}
+		} else if (!broken_filenames) {<--- Condition '!broken_filenames' is always true
+			/* name was valid, no need to re-validate */
+			validated = TRUE;
+		}
+	}
+
+	if (!validated && !g_utf8_validate (name, -1, NULL)) {
+		if (name == NULL) {
+			name = g_strdup ("[Invalid Unicode]");
+		} else {
+			utf8_name = eom_util_make_valid_utf8 (name);
+			g_free (name);
+			name = utf8_name;
+		}
+	}
+
+	priv->caption = name;
+
+	if (priv->caption == NULL) {
+		char *short_str;
+
+		short_str = g_file_get_basename (priv->file);
+		if (g_utf8_validate (short_str, -1, NULL)) {
+			priv->caption = g_strdup (short_str);
+		} else {
+			priv->caption = g_filename_to_utf8 (short_str, -1, NULL, NULL, NULL);
+		}
+		g_free (short_str);
+	}
+	g_free (scheme);
+
+	return priv->caption;
+}
+
+const gchar*
+eom_image_get_collate_key (EomImage *img)
+{
+	EomImagePrivate *priv;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	priv = img->priv;
+
+	if (priv->collate_key == NULL) {
+		const char *caption;
+
+		caption = eom_image_get_caption (img);
+
+		priv->collate_key = g_utf8_collate_key_for_filename (caption, -1);
+	}
+
+	return priv->collate_key;
+}
+
+void
+eom_image_cancel_load (EomImage *img)
+{
+	EomImagePrivate *priv;
+
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	priv = img->priv;
+
+	g_mutex_lock (&priv->status_mutex);
+
+	if (priv->status == EOM_IMAGE_STATUS_LOADING) {
+		priv->cancel_loading = TRUE;
+	}
+
+	g_mutex_unlock (&priv->status_mutex);
+}
+
+#ifdef HAVE_EXIF
+ExifData *
+eom_image_get_exif_info (EomImage *img)
+{
+	EomImagePrivate *priv;
+	ExifData *data = NULL;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	priv = img->priv;
+
+	g_mutex_lock (&priv->status_mutex);
+
+	exif_data_ref (priv->exif);
+	data = priv->exif;
+
+	g_mutex_unlock (&priv->status_mutex);
+
+	return data;
+}
+#endif
+
+/**
+ * eom_image_get_xmp_info:
+ * @img: a #EomImage
+ *
+ * Gets the XMP info for @img or NULL if compiled without
+ * libexempi support.
+ *
+ * Returns: (transfer full): the xmp data
+ **/
+gpointer
+eom_image_get_xmp_info (EomImage *img)
+{
+ 	gpointer data = NULL;
+
+ 	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+#ifdef HAVE_EXEMPI
+	EomImagePrivate *priv;
+ 	priv = img->priv;
+
+	g_mutex_lock (&priv->status_mutex);
+ 	data = (gpointer) xmp_copy (priv->xmp);
+	g_mutex_unlock (&priv->status_mutex);
+#endif
+
+ 	return data;
+}
+
+
+/**
+ * eom_image_get_file:
+ * @img: a #EomImage
+ *
+ * Gets the #GFile associated with @img
+ *
+ * Returns: (transfer full): a #GFile
+ **/
+GFile *
+eom_image_get_file (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	return g_object_ref (img->priv->file);
+}
+
+gboolean
+eom_image_is_modified (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+	return img->priv->modified;
+}
+
+goffset
+eom_image_get_bytes (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), 0);
+
+	return img->priv->bytes;
+}
+
+void
+eom_image_modified (EomImage *img)
+{
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	g_signal_emit (G_OBJECT (img), signals[SIGNAL_CHANGED], 0);
+}
+
+gchar*
+eom_image_get_uri_for_display (EomImage *img)
+{
+	EomImagePrivate *priv;
+	gchar *uri_str = NULL;
+	gchar *str = NULL;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	priv = img->priv;
+
+	if (priv->file != NULL) {
+		uri_str = g_file_get_uri (priv->file);
+
+		if (uri_str != NULL) {
+			str = g_uri_unescape_string (uri_str, NULL);
+			g_free (uri_str);
+		}
+	}
+
+	return str;
+}
+
+EomImageStatus
+eom_image_get_status (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), EOM_IMAGE_STATUS_UNKNOWN);
+
+	return img->priv->status;
+}
+
+/**
+ * eom_image_get_metadata_status:
+ * @img: a #EomImage
+ *
+ * Returns the current status of the image metadata, that is,
+ * whether the metadata has not been read yet, is ready, or not available at all.
+ *
+ * Returns: one of #EomImageMetadataStatus
+ **/
+EomImageMetadataStatus
+eom_image_get_metadata_status (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), EOM_IMAGE_METADATA_NOT_AVAILABLE);
+
+	return img->priv->metadata_status;
+}
+
+void
+eom_image_data_ref (EomImage *img)
+{
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	g_object_ref (G_OBJECT (img));
+	img->priv->data_ref_count++;
+
+	g_assert (img->priv->data_ref_count <= G_OBJECT (img)->ref_count);
+}
+
+void
+eom_image_data_unref (EomImage *img)
+{
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	if (img->priv->data_ref_count > 0) {
+		img->priv->data_ref_count--;
+	} else {
+		g_warning ("More image data unrefs than refs.");
+	}
+
+	if (img->priv->data_ref_count == 0) {
+		eom_image_free_mem_private (img);
+	}
+
+	g_object_unref (G_OBJECT (img));
+
+	g_assert (img->priv->data_ref_count <= G_OBJECT (img)->ref_count);
+}
+
+static gint
+compare_quarks (gconstpointer a, gconstpointer b)
+{
+	GQuark quark;
+
+	quark = g_quark_from_string ((const gchar *) a);
+
+	return quark - GPOINTER_TO_INT (b);
+}
+
+/**
+ * eom_image_get_supported_mime_types:
+ *
+ * Gets the list of supported mimetypes
+ *
+ * Returns: (transfer none)(element-type utf8): a #GList of supported mimetypes
+ **/
+GList *
+eom_image_get_supported_mime_types (void)
+{
+	GSList *format_list, *it;
+	gchar **mime_types;
+	int i;
+
+	if (!supported_mime_types) {
+		format_list = gdk_pixbuf_get_formats ();
+
+		for (it = format_list; it != NULL; it = it->next) {
+			mime_types =
+				gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) it->data);
+
+			for (i = 0; mime_types[i] != NULL; i++) {
+				supported_mime_types =
+					g_list_prepend (supported_mime_types,
+							g_strdup (mime_types[i]));
+			}
+
+			g_strfreev (mime_types);
+		}
+
+		supported_mime_types = g_list_sort (supported_mime_types,
+						    (GCompareFunc) compare_quarks);
+
+		g_slist_free (format_list);
+	}
+
+	return supported_mime_types;
+}
+
+gboolean
+eom_image_is_supported_mime_type (const char *mime_type)
+{
+	GList *supported_mime_types, *result;<--- Shadow variable
+	GQuark quark;
+
+	if (mime_type == NULL) {
+		return FALSE;
+	}
+
+	supported_mime_types = eom_image_get_supported_mime_types ();
+
+	quark = g_quark_from_string (mime_type);
+
+	result = g_list_find_custom (supported_mime_types,
+				     GINT_TO_POINTER (quark),
+				     (GCompareFunc) compare_quarks);
+
+	return (result != NULL);
+}
+
+static gboolean
+eom_image_iter_advance (EomImage *img)
+{
+	EomImagePrivate *priv;
+ 	gboolean new_frame;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+	g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (img->priv->anim_iter), FALSE);
+
+	priv = img->priv;
+
+	if ((new_frame = gdk_pixbuf_animation_iter_advance (img->priv->anim_iter, NULL)) == TRUE) {
+		g_mutex_lock (&priv->status_mutex);
+		g_object_unref (priv->image);
+		priv->image = gdk_pixbuf_animation_iter_get_pixbuf (priv->anim_iter);
+	 	g_object_ref (priv->image);
+		/* keep the transformation over time */
+		if (EOM_IS_TRANSFORM (priv->trans)) {
+			GdkPixbuf* transformed = eom_transform_apply (priv->trans, priv->image, NULL);
+			g_object_unref (priv->image);
+			priv->image = transformed;
+			priv->width = gdk_pixbuf_get_width (transformed);
+			priv->height = gdk_pixbuf_get_height (transformed);
+		}
+		g_mutex_unlock (&priv->status_mutex);
+		/* Emit next frame signal so we can update the display */
+		g_signal_emit (img, signals[SIGNAL_NEXT_FRAME], 0,
+			       gdk_pixbuf_animation_iter_get_delay_time (priv->anim_iter));
+	}
+
+	return new_frame;
+}
+
+/**
+ * eom_image_is_animation:
+ * @img: a #EomImage
+ *
+ * Checks whether a given image is animated.
+ *
+ * Returns: #TRUE if it is an animated image, #FALSE otherwise.
+ *
+ **/
+gboolean
+eom_image_is_animation (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+	return img->priv->anim != NULL;
+}
+
+static gboolean
+private_timeout (gpointer data)
+{
+	EomImage *img = EOM_IMAGE (data);
+	EomImagePrivate *priv = img->priv;
+
+	if (eom_image_is_animation (img) &&
+	    !g_source_is_destroyed (g_main_current_source ()) &&
+	    priv->is_playing) {
+		while (eom_image_iter_advance (img) != TRUE) {}; /* cpu-sucking ? */
+			g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (priv->anim_iter), private_timeout, img);
+	 		return FALSE;
+ 	}
+	priv->is_playing = FALSE;
+	return FALSE; /* stop playing */
+}
+
+/**
+ * eom_image_start_animation:
+ * @img: a #EomImage
+ *
+ * Starts playing an animated image.
+ *
+ * Returns: %TRUE on success, %FALSE if @img is already playing or isn't an animated image.
+ **/
+gboolean
+eom_image_start_animation (EomImage *img)
+{
+	EomImagePrivate *priv;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+	priv = img->priv;
+
+	if (!eom_image_is_animation (img) || priv->is_playing)
+		return FALSE;
+
+	g_mutex_lock (&priv->status_mutex);
+	g_object_ref (priv->anim_iter);
+	priv->is_playing = TRUE;
+	g_mutex_unlock (&priv->status_mutex);
+
+ 	g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (priv->anim_iter), private_timeout, img);
+
+	return TRUE;
+}
+
+#ifdef HAVE_RSVG
+gboolean
+eom_image_is_svg (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+	return (img->priv->svg != NULL);
+}
+
+RsvgHandle *
+eom_image_get_svg (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	return img->priv->svg;
+}
+
+#endif
+
+/**
+ * eom_image_get_transform:
+ * @img: a #EomImage
+ *
+ * Get @img transform.
+ *
+ * Returns: (transfer none): A #EomTransform.
+ */
+
+EomTransform *
+eom_image_get_transform (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	return img->priv->trans;
+}
+
+/**
+ * eom_image_get_autorotate_transform:
+ * @img: a #EomImage
+ *
+ * Get @img autorotate transform.
+ *
+ * Returns: (transfer none): A #EomTransform.
+ */
+
+EomTransform*
+eom_image_get_autorotate_transform (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	return img->priv->trans_autorotate;
+}
+
+/**
+ * eom_image_file_changed:
+ * @img: a #EomImage
+ *
+ * Marks the image files contents as changed. Also, emits
+ * EomImage::file-changed signal
+ **/
+void
+eom_image_file_changed (EomImage *img)
+{
+	g_return_if_fail (EOM_IS_IMAGE (img));
+
+	img->priv->file_is_changed = TRUE;
+	g_signal_emit (img, signals[SIGNAL_FILE_CHANGED], 0);
+}
+
+gboolean
+eom_image_is_file_changed (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), TRUE);
+
+	return img->priv->file_is_changed;
+}
+
+gboolean
+eom_image_is_jpeg (EomImage *img)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+	return ((img->priv->file_type != NULL) && (g_ascii_strcasecmp (img->priv->file_type, EOM_FILE_FORMAT_JPEG) == 0));
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/11.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/11.html new file mode 100644 index 0000000..f6e74e2 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/11.html @@ -0,0 +1,2080 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
/* Eye Of Mate - Jobs
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <lucasr@gnome.org>
+ *
+ * Based on evince code (shell/ev-jobs.c) by:
+ * 	- Martin Kretzschmar <martink@gnome.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "eom-uri-converter.h"
+#include "eom-jobs.h"
+#include "eom-job-queue.h"
+#include "eom-image.h"
+#include "eom-transform.h"
+#include "eom-list-store.h"
+#include "eom-thumbnail.h"
+#include "eom-pixbuf-util.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define EOM_JOB_GET_PRIVATE(object) \
+	(G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_JOB, EomJobPrivate))
+
+G_DEFINE_TYPE (EomJob, eom_job, G_TYPE_OBJECT);
+G_DEFINE_TYPE (EomJobThumbnail, eom_job_thumbnail, EOM_TYPE_JOB);
+G_DEFINE_TYPE (EomJobLoad, eom_job_load, EOM_TYPE_JOB);
+G_DEFINE_TYPE (EomJobModel, eom_job_model, EOM_TYPE_JOB);
+G_DEFINE_TYPE (EomJobTransform, eom_job_transform, EOM_TYPE_JOB);
+G_DEFINE_TYPE (EomJobSave, eom_job_save, EOM_TYPE_JOB);
+G_DEFINE_TYPE (EomJobSaveAs, eom_job_save_as, EOM_TYPE_JOB_SAVE);
+G_DEFINE_TYPE (EomJobCopy, eom_job_copy, EOM_TYPE_JOB);
+
+enum
+{
+	SIGNAL_FINISHED,
+	SIGNAL_PROGRESS,
+	SIGNAL_LAST_SIGNAL
+};
+
+static guint job_signals[SIGNAL_LAST_SIGNAL] = { 0 };
+
+static void eom_job_copy_run      (EomJob *ejob);
+static void eom_job_load_run 	  (EomJob *ejob);
+static void eom_job_model_run     (EomJob *ejob);
+static void eom_job_save_run      (EomJob *job);
+static void eom_job_save_as_run   (EomJob *job);
+static void eom_job_thumbnail_run (EomJob *ejob);
+static void eom_job_transform_run (EomJob *ejob);
+
+static void eom_job_init (EomJob *job)
+{
+	/* NOTE: We need to allocate the mutex here so the ABI stays the same when it used to use g_mutex_new */
+	job->mutex = g_malloc (sizeof (GMutex));
+	g_mutex_init (job->mutex);
+	job->progress = 0.0;
+}
+
+static void
+eom_job_dispose (GObject *object)
+{
+	EomJob *job;
+
+	job = EOM_JOB (object);
+
+	if (job->error) {
+		g_error_free (job->error);
+		job->error = NULL;
+	}
+
+	if (job->mutex) {
+		g_mutex_clear (job->mutex);
+		g_free (job->mutex);
+	}
+
+	(* G_OBJECT_CLASS (eom_job_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_run_default (EomJob *job)
+{
+	g_critical ("Class \"%s\" does not implement the required run action",
+		    G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (job)));
+}
+
+static void
+eom_job_class_init (EomJobClass *class)
+{
+	GObjectClass *oclass;
+
+	oclass = G_OBJECT_CLASS (class);
+
+	oclass->dispose = eom_job_dispose;
+
+	class->run = eom_job_run_default;
+
+	job_signals [SIGNAL_FINISHED] =
+		g_signal_new ("finished",
+			      EOM_TYPE_JOB,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EomJobClass, finished),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+
+	job_signals [SIGNAL_PROGRESS] =
+		g_signal_new ("progress",
+			      EOM_TYPE_JOB,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EomJobClass, progress),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__FLOAT,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_FLOAT);
+}
+
+void
+eom_job_finished (EomJob *job)
+{
+	g_return_if_fail (EOM_IS_JOB (job));
+
+	g_signal_emit (job, job_signals[SIGNAL_FINISHED], 0);
+}
+
+/**
+ * eom_job_run:
+ * @job: the job to execute.
+ *
+ * Executes the job passed as @job. Usually there is no need to call this
+ * on your own. Jobs should be executed by using the EomJobQueue.
+ **/
+void
+eom_job_run (EomJob *job)
+{
+	EomJobClass *class;
+
+	g_return_if_fail (EOM_IS_JOB (job));
+
+	class = EOM_JOB_GET_CLASS (job);
+	if (class->run)
+		class->run (job);
+	else
+		eom_job_run_default (job);
+}
+static gboolean
+notify_progress (gpointer data)
+{
+	EomJob *job = EOM_JOB (data);
+
+	g_signal_emit (job, job_signals[SIGNAL_PROGRESS], 0, job->progress);
+
+	return FALSE;
+}
+
+void
+eom_job_set_progress (EomJob *job, float progress)
+{
+	g_return_if_fail (EOM_IS_JOB (job));
+	g_return_if_fail (progress >= 0.0 && progress <= 1.0);
+
+	g_mutex_lock (job->mutex);
+	job->progress = progress;
+	g_mutex_unlock (job->mutex);
+
+	g_idle_add (notify_progress, job);
+}
+
+static void eom_job_thumbnail_init (EomJobThumbnail *job) { /* Do Nothing */ }
+
+static void
+eom_job_thumbnail_dispose (GObject *object)
+{
+	EomJobThumbnail *job;
+
+	job = EOM_JOB_THUMBNAIL (object);
+
+	if (job->image) {
+		g_object_unref (job->image);
+		job->image = NULL;
+	}
+
+	if (job->thumbnail) {
+		g_object_unref (job->thumbnail);
+		job->thumbnail = NULL;
+	}
+
+	(* G_OBJECT_CLASS (eom_job_thumbnail_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_thumbnail_class_init (EomJobThumbnailClass *class)
+{
+	GObjectClass *oclass;
+
+	oclass = G_OBJECT_CLASS (class);
+
+	oclass->dispose = eom_job_thumbnail_dispose;
+
+	EOM_JOB_CLASS (class)->run = eom_job_thumbnail_run;
+}
+
+EomJob *
+eom_job_thumbnail_new (EomImage *image)
+{
+	EomJobThumbnail *job;
+
+	job = g_object_new (EOM_TYPE_JOB_THUMBNAIL, NULL);
+
+	if (image) {
+		job->image = g_object_ref (image);
+	}
+
+	return EOM_JOB (job);
+}
+
+static void
+eom_job_thumbnail_run (EomJob *ejob)
+{
+	gchar *orig_width, *orig_height;
+	gint width, height;
+	GdkPixbuf *pixbuf;
+	EomJobThumbnail *job;
+
+	g_return_if_fail (EOM_IS_JOB_THUMBNAIL (ejob));
+
+	job = EOM_JOB_THUMBNAIL (ejob);
+
+	if (ejob->error) {
+	        g_error_free (ejob->error);
+		ejob->error = NULL;
+	}
+
+	job->thumbnail = eom_thumbnail_load (job->image,
+					     &ejob->error);
+
+	if (!job->thumbnail) {
+		ejob->finished = TRUE;
+		return;
+	}
+
+	orig_width = g_strdup (gdk_pixbuf_get_option (job->thumbnail, "tEXt::Thumb::Image::Width"));
+	orig_height = g_strdup (gdk_pixbuf_get_option (job->thumbnail, "tEXt::Thumb::Image::Height"));
+
+	pixbuf = eom_thumbnail_fit_to_size (job->thumbnail, EOM_LIST_STORE_THUMB_SIZE);
+	g_object_unref (job->thumbnail);
+	job->thumbnail = eom_thumbnail_add_frame (pixbuf);
+	g_object_unref (pixbuf);
+
+	if (orig_width) {
+		sscanf (orig_width, "%i", &width);
+		g_object_set_data (G_OBJECT (job->thumbnail),
+				   EOM_THUMBNAIL_ORIGINAL_WIDTH,
+				   GINT_TO_POINTER (width));
+		g_free (orig_width);
+	}
+	if (orig_height) {
+		sscanf (orig_height, "%i", &height);
+		g_object_set_data (G_OBJECT (job->thumbnail),
+				   EOM_THUMBNAIL_ORIGINAL_HEIGHT,
+				   GINT_TO_POINTER (height));
+		g_free (orig_height);
+	}
+
+	if (ejob->error) {
+		g_warning ("%s", ejob->error->message);
+	}
+
+	ejob->finished = TRUE;
+}
+
+static void eom_job_load_init (EomJobLoad *job) { /* Do Nothing */ }
+
+static void
+eom_job_load_dispose (GObject *object)
+{
+	EomJobLoad *job;
+
+	job = EOM_JOB_LOAD (object);
+
+	if (job->image) {
+		g_object_unref (job->image);
+		job->image = NULL;
+	}
+
+	(* G_OBJECT_CLASS (eom_job_load_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_load_class_init (EomJobLoadClass *class)
+{
+	GObjectClass *oclass;
+
+	oclass = G_OBJECT_CLASS (class);
+
+	oclass->dispose = eom_job_load_dispose;
+	EOM_JOB_CLASS (class)->run = eom_job_load_run;
+}
+
+EomJob *
+eom_job_load_new (EomImage *image, EomImageData data)
+{
+	EomJobLoad *job;
+
+	job = g_object_new (EOM_TYPE_JOB_LOAD, NULL);
+
+	if (image) {
+		job->image = g_object_ref (image);
+	}
+	job->data = data;
+
+	return EOM_JOB (job);
+}
+
+static void
+eom_job_load_run (EomJob *job)
+{
+	g_return_if_fail (EOM_IS_JOB_LOAD (job));
+
+	if (job->error) {
+	        g_error_free (job->error);
+		job->error = NULL;
+	}
+
+	eom_image_load (EOM_IMAGE (EOM_JOB_LOAD (job)->image),
+			EOM_JOB_LOAD (job)->data,
+			job,
+			&job->error);
+
+	job->finished = TRUE;
+}
+
+static void eom_job_model_init (EomJobModel *job) { /* Do Nothing */ }
+
+static void
+eom_job_model_class_init (EomJobModelClass *class)
+{
+	EOM_JOB_CLASS (class)->run = eom_job_model_run;
+}
+
+/**
+ * eom_job_model_new:
+ * @file_list: (element-type GFile): a #GFile list
+ *
+ * Creates a new #EomJob model.
+ *
+ * Returns: A #EomJob.
+ */
+
+EomJob *
+eom_job_model_new (GSList *file_list)
+{
+	EomJobModel *job;
+
+	job = g_object_new (EOM_TYPE_JOB_MODEL, NULL);
+
+	job->file_list = file_list;
+
+	return EOM_JOB (job);
+}
+
+static void
+filter_files (GSList *files, GList **file_list, GList **error_list)
+{
+	GSList *it;
+	GFileInfo *file_info;
+
+	for (it = files; it != NULL; it = it->next) {
+		GFile *file;
+		GFileType type = G_FILE_TYPE_UNKNOWN;
+
+		file = (GFile *) it->data;
+
+		if (file != NULL) {
+			file_info = g_file_query_info (file,
+						       G_FILE_ATTRIBUTE_STANDARD_TYPE","G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+						       0, NULL, NULL);
+			if (file_info == NULL) {
+				type = G_FILE_TYPE_UNKNOWN;
+			} else {
+				type = g_file_info_get_file_type (file_info);
+
+				/* Workaround for gvfs backends that
+				   don't set the GFileType. */
+				if (G_UNLIKELY (type == G_FILE_TYPE_UNKNOWN)) {
+					const gchar *ctype;
+
+					ctype = g_file_info_get_content_type (file_info);
+
+					/* If the content type is supported
+					   adjust the file_type */
+					if (eom_image_is_supported_mime_type (ctype))
+						type = G_FILE_TYPE_REGULAR;
+				}
+
+				g_object_unref (file_info);
+			}
+		}
+
+		switch (type) {
+		case G_FILE_TYPE_REGULAR:
+		case G_FILE_TYPE_DIRECTORY:
+			*file_list = g_list_prepend (*file_list, g_object_ref (file));
+			break;
+		default:
+			*error_list = g_list_prepend (*error_list,
+						      g_file_get_uri (file));
+			break;
+		}
+	}
+
+	*file_list  = g_list_reverse (*file_list);
+	*error_list = g_list_reverse (*error_list);
+}
+
+static void
+eom_job_model_run (EomJob *ejob)
+{
+	GList *filtered_list = NULL;
+	GList *error_list = NULL;
+	EomJobModel *job;
+
+	g_return_if_fail (EOM_IS_JOB_MODEL (ejob));
+
+	job = EOM_JOB_MODEL (ejob);
+
+	filter_files (job->file_list, &filtered_list, &error_list);
+
+	job->store = EOM_LIST_STORE (eom_list_store_new ());
+
+	eom_list_store_add_files (job->store, filtered_list);
+
+	g_list_free_full (filtered_list, g_object_unref);
+	g_list_free_full (error_list, g_free);
+
+	ejob->finished = TRUE;
+}
+
+static void eom_job_transform_init (EomJobTransform *job) { /* Do Nothing */ }
+
+static void
+eom_job_transform_dispose (GObject *object)
+{
+	EomJobTransform *job;
+
+	job = EOM_JOB_TRANSFORM (object);
+
+	if (job->trans) {
+		g_object_unref (job->trans);
+		job->trans = NULL;
+	}
+
+	g_list_free_full (job->images, g_object_unref);
+
+	(* G_OBJECT_CLASS (eom_job_transform_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_transform_class_init (EomJobTransformClass *class)
+{
+	GObjectClass *oclass;
+
+	oclass = G_OBJECT_CLASS (class);
+
+	oclass->dispose = eom_job_transform_dispose;
+
+	EOM_JOB_CLASS (class)->run = eom_job_transform_run;
+}
+
+/**
+ * eom_job_transform_new:
+ * @images: (element-type EomImage) (transfer full): a #EomImage list
+ * @trans: a #EomTransform
+ *
+ * Create a new #EomJob for image transformation.
+ *
+ * Returns: A #EomJob.
+ */
+
+EomJob *
+eom_job_transform_new (GList *images, EomTransform *trans)
+{
+	EomJobTransform *job;
+
+	job = g_object_new (EOM_TYPE_JOB_TRANSFORM, NULL);
+
+	if (trans) {
+		job->trans = g_object_ref (trans);
+	} else {
+		job->trans = NULL;
+	}
+
+	job->images = images;
+
+	return EOM_JOB (job);
+}
+
+static gboolean
+eom_job_transform_image_modified (gpointer data)
+{
+	g_return_val_if_fail (EOM_IS_IMAGE (data), FALSE);
+
+	eom_image_modified (EOM_IMAGE (data));
+	g_object_unref (G_OBJECT (data));
+
+	return FALSE;
+}
+
+void
+eom_job_transform_run (EomJob *ejob)
+{
+	EomJobTransform *job;
+	GList *it;
+
+	g_return_if_fail (EOM_IS_JOB_TRANSFORM (ejob));
+
+	job = EOM_JOB_TRANSFORM (ejob);
+
+	if (ejob->error) {
+	        g_error_free (ejob->error);
+		ejob->error = NULL;
+	}
+
+	for (it = job->images; it != NULL; it = it->next) {
+		EomImage *image = EOM_IMAGE (it->data);
+
+		if (job->trans == NULL) {
+			eom_image_undo (image);
+		} else {
+			eom_image_transform (image, job->trans, ejob);
+		}
+
+		if (eom_image_is_modified (image) || job->trans == NULL) {
+			g_object_ref (image);
+			g_idle_add (eom_job_transform_image_modified, image);
+		}
+	}
+
+	ejob->finished = TRUE;
+}
+
+static void eom_job_save_init (EomJobSave *job) { /* do nothing */ }
+
+static void
+eom_job_save_dispose (GObject *object)
+{
+	EomJobSave *job;
+
+	job = EOM_JOB_SAVE (object);
+
+	if (job->images) {
+		g_list_free_full (job->images, g_object_unref);
+		job->images = NULL;
+	}
+
+	(* G_OBJECT_CLASS (eom_job_save_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_save_class_init (EomJobSaveClass *class)
+{
+	G_OBJECT_CLASS (class)->dispose = eom_job_save_dispose;
+	EOM_JOB_CLASS (class)->run = eom_job_save_run;
+}
+
+/**
+ * eom_job_save_new:
+ * @images: (element-type EomImage) (transfer full): a #EomImage list
+ *
+ * Creates a new #EomJob for image saving.
+ *
+ * Returns: A #EomJob.
+ */
+
+EomJob *
+eom_job_save_new (GList *images)
+{
+	EomJobSave *job;
+
+	job = g_object_new (EOM_TYPE_JOB_SAVE, NULL);
+
+	job->images = images;
+	job->current_image = NULL;
+
+	return EOM_JOB (job);
+}
+
+static void
+save_progress_handler (EomImage *image, gfloat progress, gpointer data)
+{
+	EomJobSave *job = EOM_JOB_SAVE (data);
+	guint n_images = g_list_length (job->images);
+	gfloat job_progress;
+
+	job_progress = (job->current_pos / (gfloat) n_images) + (progress / n_images);
+
+	eom_job_set_progress (EOM_JOB (job), job_progress);
+}
+
+static void
+eom_job_save_run (EomJob *ejob)
+{
+	EomJobSave *job;
+	GList *it;
+
+	g_return_if_fail (EOM_IS_JOB_SAVE (ejob));
+
+	job = EOM_JOB_SAVE (ejob);
+
+	job->current_pos = 0;
+
+	for (it = job->images; it != NULL; it = it->next, job->current_pos++) {
+		EomImage *image = EOM_IMAGE (it->data);
+		EomImageSaveInfo *save_info = NULL;
+		gulong handler_id = 0;
+		gboolean success = FALSE;
+
+		job->current_image = image;
+
+		/* Make sure the image doesn't go away while saving */
+		eom_image_data_ref (image);
+
+		if (!eom_image_has_data (image, EOM_IMAGE_DATA_ALL)) {
+			EomImageMetadataStatus m_status;
+			gint data2load = 0;
+
+			m_status = eom_image_get_metadata_status (image);
+			if (!eom_image_has_data (image, EOM_IMAGE_DATA_IMAGE)) {
+				// Queue full read in this case
+				data2load = EOM_IMAGE_DATA_ALL;
+			} else if (m_status == EOM_IMAGE_METADATA_NOT_READ) {
+				// Load only if we haven't read it yet
+				data2load = EOM_IMAGE_DATA_EXIF | EOM_IMAGE_DATA_XMP;
+			}
+
+			if (data2load != 0) {
+				eom_image_load (image,
+						data2load,
+						NULL,
+						&ejob->error);
+			}
+		}
+
+		handler_id = g_signal_connect (G_OBJECT (image),
+					       "save-progress",
+				               G_CALLBACK (save_progress_handler),
+					       job);
+
+		save_info = eom_image_save_info_new_from_image (image);
+
+		success = eom_image_save_by_info (image,
+						  save_info,
+						  &ejob->error);
+
+		if (save_info)
+			g_object_unref (save_info);
+
+		if (handler_id != 0)
+			g_signal_handler_disconnect (G_OBJECT (image), handler_id);
+
+		eom_image_data_unref (image);
+
+		if (!success) break;
+	}
+
+	ejob->finished = TRUE;
+}
+
+static void eom_job_save_as_init (EomJobSaveAs *job) { /* do nothing */ }
+
+static void eom_job_save_as_dispose (GObject *object)
+{
+	EomJobSaveAs *job = EOM_JOB_SAVE_AS (object);
+
+	if (job->converter != NULL) {
+		g_object_unref (job->converter);
+		job->converter = NULL;
+	}
+
+	if (job->file != NULL) {
+		g_object_unref (job->file);
+		job->file = NULL;
+	}
+
+	(* G_OBJECT_CLASS (eom_job_save_as_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_save_as_class_init (EomJobSaveAsClass *class)
+{
+	G_OBJECT_CLASS (class)->dispose = eom_job_save_as_dispose;
+	EOM_JOB_CLASS (class)->run = eom_job_save_as_run;
+}
+
+/**
+ * eom_job_save_as_new:
+ * @images: (element-type EomImage) (transfer full): a #EomImage list
+ * @converter: a URI converter
+ * file: a #GFile
+ *
+ * Creates a new #EomJob for save as.
+ *
+ * Returns: A #EomJob.
+ */
+
+EomJob *
+eom_job_save_as_new (GList *images, EomURIConverter *converter, GFile *file)
+{
+	EomJobSaveAs *job;
+
+	g_assert (converter != NULL || g_list_length (images) == 1);
+
+	job = g_object_new (EOM_TYPE_JOB_SAVE_AS, NULL);
+
+	EOM_JOB_SAVE(job)->images = images;
+
+	job->converter = converter ? g_object_ref (converter) : NULL;
+	job->file = file ? g_object_ref (file) : NULL;
+
+	return EOM_JOB (job);
+}
+
+static void
+eom_job_save_as_run (EomJob *ejob)
+{
+	EomJobSave *job;
+	EomJobSaveAs *saveas_job;
+	GList *it;
+	guint n_images;
+
+	g_return_if_fail (EOM_IS_JOB_SAVE_AS (ejob));
+
+	job = EOM_JOB_SAVE (ejob);
+
+	n_images = g_list_length (job->images);
+
+	saveas_job = EOM_JOB_SAVE_AS (job);
+
+	job->current_pos = 0;
+
+	for (it = job->images; it != NULL; it = it->next, job->current_pos++) {
+		GdkPixbufFormat *format;
+		EomImageSaveInfo *src_info, *dest_info;
+		EomImage *image = EOM_IMAGE (it->data);
+		gboolean success = FALSE;
+		gulong handler_id = 0;
+
+		job->current_image = image;
+
+		eom_image_data_ref (image);
+
+		if (!eom_image_has_data (image, EOM_IMAGE_DATA_ALL)) {
+			EomImageMetadataStatus m_status;
+			gint data2load = 0;
+
+			m_status = eom_image_get_metadata_status (image);
+			if (!eom_image_has_data (image, EOM_IMAGE_DATA_IMAGE)) {
+				// Queue full read in this case
+				data2load = EOM_IMAGE_DATA_ALL;
+			} else if (m_status == EOM_IMAGE_METADATA_NOT_READ) {
+				// Load only if we haven't read it yet
+				data2load = EOM_IMAGE_DATA_EXIF | EOM_IMAGE_DATA_XMP;
+			}
+
+			if (data2load != 0) {
+				eom_image_load (image,
+						data2load,
+						NULL,
+						&ejob->error);
+			}
+		}
+
+		g_assert (ejob->error == NULL);
+
+		handler_id = g_signal_connect (G_OBJECT (image),
+					       "save-progress",
+				               G_CALLBACK (save_progress_handler),
+					       job);
+
+		src_info = eom_image_save_info_new_from_image (image);
+
+		if (n_images == 1) {
+			g_assert (saveas_job->file != NULL);
+
+			format = eom_pixbuf_get_format (saveas_job->file);
+
+			dest_info = eom_image_save_info_new_from_file (saveas_job->file,
+								   format);
+
+		/* SaveAsDialog has already secured permission to overwrite */
+			if (dest_info->exists) {
+				dest_info->overwrite = TRUE;
+			}
+		} else {
+			GFile *dest_file;
+			gboolean result;
+
+			result = eom_uri_converter_do (saveas_job->converter,
+						       image,
+						       &dest_file,
+						       &format,
+						       NULL);
+
+			g_assert (result);
+
+			dest_info = eom_image_save_info_new_from_file (dest_file,
+								   format);
+		}
+
+		success = eom_image_save_as_by_info (image,
+						     src_info,
+						     dest_info,
+						     &ejob->error);
+
+		if (src_info)
+			g_object_unref (src_info);
+
+		if (dest_info)
+			g_object_unref (dest_info);
+
+		if (handler_id != 0)
+			g_signal_handler_disconnect (G_OBJECT (image), handler_id);
+
+		eom_image_data_unref (image);
+
+		if (!success)
+			break;
+	}
+
+	ejob->finished = TRUE;
+}
+
+static void eom_job_copy_init (EomJobCopy *job) { /* do nothing */};
+
+static void
+eom_job_copy_dispose (GObject *object)
+{
+	EomJobCopy *job = EOM_JOB_COPY (object);
+
+	if (job->dest) {
+		g_free (job->dest);
+		job->dest = NULL;
+	}
+
+	(* G_OBJECT_CLASS (eom_job_copy_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_copy_class_init (EomJobCopyClass *class)
+{
+	G_OBJECT_CLASS (class)->dispose = eom_job_copy_dispose;
+	EOM_JOB_CLASS (class)->run = eom_job_copy_run;
+}
+
+/**
+ * eom_job_copy_new:
+ * @images: (element-type EomImage) (transfer full): a #EomImage list
+ * @dest: destination path for the copy
+ *
+ * Creates a new #EomJob.
+ *
+ * Returns: A #EomJob.
+ */
+
+EomJob *
+eom_job_copy_new (GList *images, const gchar *dest)
+{
+	EomJobCopy *job;
+
+	g_assert (images != NULL && dest != NULL);
+
+	job = g_object_new (EOM_TYPE_JOB_COPY, NULL);
+
+	job->images = images;
+	job->dest = g_strdup (dest);
+
+	return EOM_JOB (job);
+}
+
+static void
+eom_job_copy_progress_callback (goffset current_num_bytes,
+				goffset total_num_bytes,
+				gpointer user_data)
+{
+	gfloat job_progress;
+	guint n_images;
+	EomJobCopy *job;
+
+	job = EOM_JOB_COPY (user_data);
+	n_images = g_list_length (job->images);
+
+	job_progress =  ((current_num_bytes / (gfloat) total_num_bytes) + job->current_pos)/n_images;
+
+	eom_job_set_progress (EOM_JOB (job), job_progress);
+}
+
+void
+eom_job_copy_run (EomJob *ejob)
+{
+	EomJobCopy *job;
+	GList *it;
+	GFile *src, *dest;
+	gchar *filename, *dest_filename;
+
+	g_return_if_fail (EOM_IS_JOB_COPY (ejob));
+
+	job = EOM_JOB_COPY (ejob);
+
+	job->current_pos = 0;
+
+	for (it = job->images; it != NULL; it = g_list_next (it), job->current_pos++) {
+		src = (GFile *) it->data;
+		filename = g_file_get_basename (src);
+		dest_filename = g_build_filename (job->dest, filename, NULL);
+		dest = g_file_new_for_path (dest_filename);
+
+		g_file_copy (src, dest,
+			     G_FILE_COPY_OVERWRITE, NULL,
+			     eom_job_copy_progress_callback, job,
+			     &ejob->error);
+		g_free (filename);
+		g_free (dest_filename);
+	}
+
+	ejob->finished = TRUE;
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/12.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/12.html new file mode 100644 index 0000000..b57ae6b --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/12.html @@ -0,0 +1,2056 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
/* Eye Of Mate - Image Store
+ *
+ * Copyright (C) 2006-2008 The Free Software Foundation
+ *
+ * Author: Claudio Saavedra <csaavedra@gnome.org>
+ *
+ * Based on code by: Jens Finke <jens@triq.net>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "eom-list-store.h"
+#include "eom-thumbnail.h"
+#include "eom-image.h"
+#include "eom-job-queue.h"
+#include "eom-jobs.h"
+
+#include <string.h>
+
+#define EOM_LIST_STORE_GET_PRIVATE(object) \
+	(G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_LIST_STORE, EomListStorePrivate))
+
+struct _EomListStorePrivate {
+	GList *monitors;          /* Monitors for the directories */
+	gint initial_image;       /* The image that should be selected firstly by the view. */
+	GdkPixbuf *busy_image;    /* Loading image icon */
+	GdkPixbuf *missing_image; /* Missing image icon */
+	GMutex mutex;            /* Mutex for saving the jobs in the model */
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomListStore, eom_list_store, GTK_TYPE_LIST_STORE);
+
+static void
+foreach_monitors_free (gpointer data, gpointer user_data)
+{
+	g_file_monitor_cancel (G_FILE_MONITOR (data));
+}
+
+static void
+eom_list_store_dispose (GObject *object)
+{
+	EomListStore *store = EOM_LIST_STORE (object);
+
+	g_list_foreach (store->priv->monitors,
+			foreach_monitors_free, NULL);
+
+	g_list_free (store->priv->monitors);
+
+	store->priv->monitors = NULL;
+
+	if(store->priv->busy_image != NULL) {
+		g_object_unref (store->priv->busy_image);
+		store->priv->busy_image = NULL;
+	}
+
+	if(store->priv->missing_image != NULL) {
+		g_object_unref (store->priv->missing_image);
+		store->priv->missing_image = NULL;
+	}
+
+	g_mutex_clear (&store->priv->mutex);
+
+	G_OBJECT_CLASS (eom_list_store_parent_class)->dispose (object);
+}
+
+static void
+eom_list_store_class_init (EomListStoreClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->dispose = eom_list_store_dispose;
+}
+
+/*
+   Sorting functions
+*/
+
+static gint
+eom_list_store_compare_func (GtkTreeModel *model,
+			     GtkTreeIter *a,
+			     GtkTreeIter *b,
+			     gpointer user_data)
+{
+	gint r_value;
+
+	EomImage *image_a, *image_b;
+
+	gtk_tree_model_get (model, a,
+			    EOM_LIST_STORE_EOM_IMAGE, &image_a,
+			    -1);
+
+	gtk_tree_model_get (model, b,
+			    EOM_LIST_STORE_EOM_IMAGE, &image_b,
+			    -1);
+
+	r_value = strcmp (eom_image_get_collate_key (image_a),
+			  eom_image_get_collate_key (image_b));
+
+	g_object_unref (G_OBJECT (image_a));
+	g_object_unref (G_OBJECT (image_b));
+
+	return r_value;
+}
+
+static GdkPixbuf *
+eom_list_store_get_icon (const gchar *icon_name)
+{
+	GError *error = NULL;
+	GtkIconTheme *icon_theme;
+	GdkPixbuf *pixbuf;
+
+	icon_theme = gtk_icon_theme_get_default ();
+
+	pixbuf = gtk_icon_theme_load_icon (icon_theme,
+					   icon_name,
+					   EOM_LIST_STORE_THUMB_SIZE,
+					   0,
+					   &error);
+
+	if (!pixbuf) {
+		g_warning ("Couldn't load icon: %s", error->message);
+		g_error_free (error);
+	}
+
+	return pixbuf;
+}
+
+static void
+eom_list_store_init (EomListStore *self)
+{
+	GType types[EOM_LIST_STORE_NUM_COLUMNS];
+
+	types[EOM_LIST_STORE_THUMBNAIL] = GDK_TYPE_PIXBUF;
+	types[EOM_LIST_STORE_EOM_IMAGE] = G_TYPE_OBJECT;
+	types[EOM_LIST_STORE_THUMB_SET] = G_TYPE_BOOLEAN;
+	types[EOM_LIST_STORE_EOM_JOB]   = G_TYPE_POINTER;
+
+	gtk_list_store_set_column_types (GTK_LIST_STORE (self),
+					 EOM_LIST_STORE_NUM_COLUMNS, types);
+
+	self->priv = eom_list_store_get_instance_private (self);
+
+	self->priv->monitors = NULL;
+	self->priv->initial_image = -1;
+
+	self->priv->busy_image = eom_list_store_get_icon ("image-loading");
+	self->priv->missing_image = eom_list_store_get_icon ("image-missing");
+
+	g_mutex_init (&self->priv->mutex);
+
+	gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (self),
+						 eom_list_store_compare_func,
+						 NULL, NULL);
+
+	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self),
+					      GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+					      GTK_SORT_ASCENDING);
+}
+
+/**
+ * eom_list_store_new:
+ *
+ * Creates a new and empty #EomListStore.
+ *
+ * Returns: a newly created #EomListStore.
+ **/
+GtkListStore*
+eom_list_store_new (void)
+{
+        return g_object_new (EOM_TYPE_LIST_STORE, NULL);
+}
+
+/*
+   Searchs for a file in the store. If found and @iter_found is not NULL,
+   then sets @iter_found to a #GtkTreeIter pointing to the file.
+ */
+static gboolean
+is_file_in_list_store (EomListStore *store,
+		       const gchar *info_uri,
+		       GtkTreeIter *iter_found)
+{
+	gboolean found = FALSE;
+	EomImage *image;
+	GFile *file;
+	gchar *str;
+	GtkTreeIter iter;
+
+	if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
+		return FALSE;
+	}
+
+	do {
+		gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+				    EOM_LIST_STORE_EOM_IMAGE, &image,
+				    -1);
+		if (!image)
+			continue;
+
+		file = eom_image_get_file (image);
+		str = g_file_get_uri (file);
+
+		found = (strcmp (str, info_uri) == 0)? TRUE : FALSE;
+
+		g_object_unref (file);
+		g_free (str);
+		g_object_unref (G_OBJECT (image));
+
+	} while (!found &&
+		 gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
+
+	if (found && iter_found != NULL) {
+		*iter_found = iter;
+	}
+
+	return found;
+}
+
+static gboolean
+is_file_in_list_store_file (EomListStore *store,
+			   GFile *file,
+			   GtkTreeIter *iter_found)
+{
+	gchar *uri_str;
+	gboolean result;
+
+	uri_str = g_file_get_uri (file);
+
+	result = is_file_in_list_store (store, uri_str, iter_found);
+
+	g_free (uri_str);
+
+	return result;
+}
+
+static void
+eom_job_thumbnail_cb (EomJobThumbnail *job, gpointer data)
+{
+	EomListStore *store;
+	GtkTreeIter iter;
+	EomImage *image;
+	GdkPixbuf *thumbnail;
+	GFile *file;
+
+	g_return_if_fail (EOM_IS_LIST_STORE (data));
+
+	store = EOM_LIST_STORE (data);
+
+	file = eom_image_get_file (job->image);
+
+	if (is_file_in_list_store_file (store, file, &iter)) {
+		gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+				    EOM_LIST_STORE_EOM_IMAGE, &image,
+				    -1);
+
+		if (job->thumbnail) {
+			eom_image_set_thumbnail (image, job->thumbnail);
+
+			/* Getting the thumbnail, in case it needed
+ 			 * transformations */
+			thumbnail = eom_image_get_thumbnail (image);
+		} else {
+			thumbnail = g_object_ref (store->priv->missing_image);
+		}
+
+		gtk_list_store_set (GTK_LIST_STORE (store), &iter,
+				    EOM_LIST_STORE_THUMBNAIL, thumbnail,
+				    EOM_LIST_STORE_THUMB_SET, TRUE,
+				    EOM_LIST_STORE_EOM_JOB, NULL,
+				    -1);
+		g_object_unref (image);
+		g_object_unref (thumbnail);
+	}
+
+	g_object_unref (file);
+}
+
+static void
+on_image_changed (EomImage *image, EomListStore *store)
+{
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	gint pos;
+
+	pos = eom_list_store_get_pos_by_image (store, image);
+	path = gtk_tree_path_new_from_indices (pos, -1);
+
+	gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
+	eom_list_store_thumbnail_refresh (store, &iter);
+	gtk_tree_path_free (path);
+}
+
+/**
+ * eom_list_store_remove:
+ * @store: An #EomListStore.
+ * @iter: A #GtkTreeIter.
+ *
+ * Removes the image pointed by @iter from @store.
+ **/
+static void
+eom_list_store_remove (EomListStore *store, GtkTreeIter *iter)
+{
+	EomImage *image;
+
+	gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+			    EOM_LIST_STORE_EOM_IMAGE, &image,
+			    -1);
+
+	g_signal_handlers_disconnect_by_func (image, on_image_changed, store);
+	g_object_unref (image);
+
+	gtk_list_store_remove (GTK_LIST_STORE (store), iter);
+}
+
+/**
+ * eom_list_store_append_image:
+ * @store: An #EomListStore.
+ * @image: An #EomImage.
+ *
+ * Adds an #EomImage to @store. The thumbnail of the image is not
+ * loaded and will only be loaded if the thumbnail is made visible
+ * or eom_list_store_set_thumbnail() is called.
+ *
+ **/
+void
+eom_list_store_append_image (EomListStore *store, EomImage *image)
+{
+	GtkTreeIter iter;
+
+	g_signal_connect (image, "changed",
+ 			  G_CALLBACK (on_image_changed),
+ 			  store);
+
+	gtk_list_store_append (GTK_LIST_STORE (store), &iter);
+	gtk_list_store_set (GTK_LIST_STORE (store), &iter,
+			    EOM_LIST_STORE_EOM_IMAGE, image,
+			    EOM_LIST_STORE_THUMBNAIL, store->priv->busy_image,
+			    EOM_LIST_STORE_THUMB_SET, FALSE,
+			    -1);
+}
+
+static void
+eom_list_store_append_image_from_file (EomListStore *store,
+				       GFile *file,
+				       const gchar *caption)
+{
+	EomImage *image;
+
+	g_return_if_fail (EOM_IS_LIST_STORE (store));
+
+	image = eom_image_new_file (file, caption);
+
+	eom_list_store_append_image (store, image);
+}
+
+static void
+file_monitor_changed_cb (GFileMonitor *monitor,
+			 GFile *file,
+			 GFile *other_file,
+			 GFileMonitorEvent event,
+			 EomListStore *store)
+{
+	const char *mimetype;
+	GFileInfo *file_info;
+	GtkTreeIter iter;
+	EomImage *image;<--- Shadowed declaration
+
+	switch (event) {
+	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+		file_info = g_file_query_info (file,
+					       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
+					       G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+					       0, NULL, NULL);
+		if (file_info == NULL) {
+			break;
+		}
+		mimetype = g_file_info_get_content_type (file_info);
+
+		if (is_file_in_list_store_file (store, file, &iter)) {
+			if (eom_image_is_supported_mime_type (mimetype)) {
+				gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+						    EOM_LIST_STORE_EOM_IMAGE, &image,
+						    -1);
+				eom_image_file_changed (image);
+				g_object_unref (image);
+				eom_list_store_thumbnail_refresh (store, &iter);
+			} else {
+				eom_list_store_remove (store, &iter);
+			}
+		} else {
+			if (eom_image_is_supported_mime_type (mimetype)) {
+				const gchar *caption;
+
+				caption = g_file_info_get_display_name (file_info);
+				eom_list_store_append_image_from_file (store, file, caption);
+			}
+		}
+		g_object_unref (file_info);
+		break;
+	case G_FILE_MONITOR_EVENT_DELETED:
+		if (is_file_in_list_store_file (store, file, &iter)) {
+			EomImage *image;<--- Shadow variable
+
+			gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+					    EOM_LIST_STORE_EOM_IMAGE, &image,
+					    -1);
+
+			eom_list_store_remove (store, &iter);
+		}
+		break;
+	case G_FILE_MONITOR_EVENT_CREATED:
+		if (!is_file_in_list_store_file (store, file, NULL)) {
+			file_info = g_file_query_info (file,
+						       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
+						       G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+						       0, NULL, NULL);
+			if (file_info == NULL) {
+				break;
+			}
+			mimetype = g_file_info_get_content_type (file_info);
+
+			if (eom_image_is_supported_mime_type (mimetype)) {
+				const gchar *caption;
+
+				caption = g_file_info_get_display_name (file_info);
+				eom_list_store_append_image_from_file (store, file, caption);
+			}
+			g_object_unref (file_info);
+		}
+		break;
+	case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+		file_info = g_file_query_info (file,
+					       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+					       0, NULL, NULL);
+		if (file_info == NULL) {
+			break;
+		}
+		mimetype = g_file_info_get_content_type (file_info);
+		if (is_file_in_list_store_file (store, file, &iter) &&
+		    eom_image_is_supported_mime_type (mimetype)) {
+			eom_list_store_thumbnail_refresh (store, &iter);
+		}
+		g_object_unref (file_info);
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * Called for each file in a directory. Checks if the file is some
+ * sort of image. If so, it creates an image object and adds it to the
+ * list.
+ */
+static void
+directory_visit (GFile *directory,
+		 GFileInfo *children_info,
+		 EomListStore *store)
+{
+	GFile *child;
+	gboolean load_uri = FALSE;
+	const char *mime_type, *name;
+
+	mime_type = g_file_info_get_content_type (children_info);
+	name = g_file_info_get_name (children_info);
+
+	if (!g_str_has_prefix (name, ".")) {
+		/* We support opening any image type, so let eom to add any images in the current directory to the store */
+		if (g_content_type_is_mime_type (mime_type, "image/*") || eom_image_is_supported_mime_type (mime_type)) {
+			load_uri = TRUE;
+		}
+	}
+
+	if (load_uri) {
+		const gchar *caption;
+
+		child = g_file_get_child (directory, name);
+		caption = g_file_info_get_display_name (children_info);
+		eom_list_store_append_image_from_file (store, child, caption);
+	}
+}
+
+static void
+eom_list_store_append_directory (EomListStore *store,
+				 GFile *file,
+				 GFileType file_type)
+{
+	GFileMonitor *file_monitor;
+	GFileEnumerator *file_enumerator;
+	GFileInfo *file_info;
+
+	g_return_if_fail (file_type == G_FILE_TYPE_DIRECTORY);
+
+	file_monitor = g_file_monitor_directory (file,
+						 0, NULL, NULL);
+
+	if (file_monitor != NULL) {
+		g_signal_connect (file_monitor, "changed",
+				  G_CALLBACK (file_monitor_changed_cb), store);
+
+		/* prepend seems more efficient to me, we don't need this list
+		   to be sorted */
+		store->priv->monitors = g_list_prepend (store->priv->monitors, file_monitor);
+	}
+
+	file_enumerator = g_file_enumerate_children (file,
+						     G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
+						     G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
+						     G_FILE_ATTRIBUTE_STANDARD_NAME,
+						     0, NULL, NULL);
+	file_info = g_file_enumerator_next_file (file_enumerator, NULL, NULL);
+
+	while (file_info != NULL)
+	{
+		directory_visit (file, file_info, store);
+		g_object_unref (file_info);
+		file_info = g_file_enumerator_next_file (file_enumerator, NULL, NULL);
+	}
+	g_object_unref (file_enumerator);
+}
+
+/**
+ * eom_list_store_add_files:
+ * @store: An #EomListStore.
+ * @file_list: (element-type GFile): A %NULL-terminated list of #GFile's.
+ *
+ * Adds a list of #GFile's to @store. The given list
+ * must be %NULL-terminated.
+ *
+ * If any of the #GFile's in @file_list is a directory, all the images
+ * in that directory will be added to @store. If the list of files contains
+ * only one file and this is a regular file, then all the images in the same
+ * directory will be added as well to @store.
+ *
+ **/
+void
+eom_list_store_add_files (EomListStore *store, GList *file_list)
+{
+	GList *it;
+	GFileInfo *file_info;
+	GFileType file_type;
+	GFile *initial_file = NULL;
+	GtkTreeIter iter;
+
+	if (file_list == NULL) {
+		return;
+	}
+
+	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+					      GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
+					      GTK_SORT_ASCENDING);
+
+	for (it = file_list; it != NULL; it = it->next) {
+		GFile *file = (GFile *) it->data;
+		gchar *caption = NULL;
+
+		file_info = g_file_query_info (file,
+					       G_FILE_ATTRIBUTE_STANDARD_TYPE","
+					       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE","
+					       G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+					       0, NULL, NULL);
+		if (file_info == NULL) {
+			continue;
+		}
+
+		caption = g_strdup (g_file_info_get_display_name (file_info));
+		file_type = g_file_info_get_file_type (file_info);
+
+		/* Workaround for gvfs backends that don't set the GFileType. */
+		if (G_UNLIKELY (file_type == G_FILE_TYPE_UNKNOWN)) {
+			const gchar *ctype;
+
+			ctype = g_file_info_get_content_type (file_info);
+
+			/* If the content type is supported adjust file_type */
+			if (eom_image_is_supported_mime_type (ctype))
+				file_type = G_FILE_TYPE_REGULAR;
+		}
+
+		g_object_unref (file_info);
+
+		if (file_type == G_FILE_TYPE_DIRECTORY) {
+			eom_list_store_append_directory (store, file, file_type);
+		} else if (file_type == G_FILE_TYPE_REGULAR &&
+			   g_list_length (file_list) == 1) {
+
+			initial_file = g_file_dup (file);
+
+			file = g_file_get_parent (file);
+			file_info = g_file_query_info (file,
+						       G_FILE_ATTRIBUTE_STANDARD_TYPE,
+						       0, NULL, NULL);
+
+			/* If we can't get a file_info,
+			   file_type will stay as G_FILE_TYPE_REGULAR */
+			if (file_info != NULL) {
+				file_type = g_file_info_get_file_type (file_info);
+				g_object_unref (file_info);
+			}
+
+			if (file_type == G_FILE_TYPE_DIRECTORY) {
+				eom_list_store_append_directory (store, file, file_type);
+
+				if (!is_file_in_list_store_file (store,
+								 initial_file,
+								 &iter)) {
+					eom_list_store_append_image_from_file (store, initial_file, caption);
+				}
+			} else {
+				eom_list_store_append_image_from_file (store, initial_file, caption);
+			}
+			g_object_unref (file);
+		} else if (file_type == G_FILE_TYPE_REGULAR &&
+			   g_list_length (file_list) > 1) {
+			eom_list_store_append_image_from_file (store, file, caption);
+		}
+
+		g_free (caption);
+	}
+
+	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+					      GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+					      GTK_SORT_ASCENDING);
+
+	if (initial_file &&
+	    is_file_in_list_store_file (store, initial_file, &iter)) {
+		store->priv->initial_image = eom_list_store_get_pos_by_iter (store, &iter);
+		g_object_unref (initial_file);
+	} else {
+		store->priv->initial_image = 0;
+	}
+}
+
+/**
+ * eom_list_store_remove_image:
+ * @store: An #EomListStore.
+ * @image: An #EomImage.
+ *
+ * Removes @image from @store.
+ **/
+void
+eom_list_store_remove_image (EomListStore *store, EomImage *image)
+{
+	GtkTreeIter iter;
+	GFile *file;
+
+	g_return_if_fail (EOM_IS_LIST_STORE (store));
+	g_return_if_fail (EOM_IS_IMAGE (image));
+
+	file = eom_image_get_file (image);
+
+	if (is_file_in_list_store_file (store, file, &iter)) {
+		eom_list_store_remove (store, &iter);
+	}
+	g_object_unref (file);
+}
+
+/**
+ * eom_list_store_new_from_glist:
+ * @list: (element-type EomImage): a %NULL-terminated list of #EomImage's.
+ *
+ * Creates a new #EomListStore from a list of #EomImage's.
+ * The given list must be %NULL-terminated.
+ *
+ * Returns: a new #EomListStore.
+ **/
+GtkListStore *
+eom_list_store_new_from_glist (GList *list)
+{
+	GList *it;
+
+	GtkListStore *store = eom_list_store_new ();
+
+	for (it = list; it != NULL; it = it->next) {
+		eom_list_store_append_image (EOM_LIST_STORE (store),
+					     EOM_IMAGE (it->data));
+	}
+
+	return store;
+}
+
+/**
+ * eom_list_store_get_pos_by_image:
+ * @store: An #EomListStore.
+ * @image: An #EomImage.
+ *
+ * Gets the position where @image is stored in @store. If @image
+ * is not stored in @store, -1 is returned.
+ *
+ * Returns: the position of @image in @store or -1 if not found.
+ **/
+gint
+eom_list_store_get_pos_by_image (EomListStore *store, EomImage *image)
+{
+	GtkTreeIter iter;
+	gint pos = -1;
+	GFile *file;
+
+	g_return_val_if_fail (EOM_IS_LIST_STORE (store), -1);
+	g_return_val_if_fail (EOM_IS_IMAGE (image), -1);
+
+	file = eom_image_get_file (image);
+
+	if (is_file_in_list_store_file (store, file, &iter)) {
+		pos = eom_list_store_get_pos_by_iter (store, &iter);
+	}
+
+	g_object_unref (file);
+	return pos;
+}
+
+/**
+ * eom_list_store_get_image_by_pos:
+ * @store: An #EomListStore.
+ * @pos: the position of the required #EomImage.
+ *
+ * Gets the #EomImage in the position @pos of @store. If there is
+ * no image at position @pos, %NULL is returned.
+ *
+ * Returns: (transfer full): the #EomImage in position @pos or %NULL.
+ *
+ **/
+EomImage *
+eom_list_store_get_image_by_pos (EomListStore *store, gint pos)
+{
+	EomImage *image = NULL;
+	GtkTreeIter iter;
+
+	g_return_val_if_fail (EOM_IS_LIST_STORE (store), NULL);
+
+	if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, NULL, pos)) {
+		gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+				    EOM_LIST_STORE_EOM_IMAGE, &image,
+				    -1);
+	}
+
+	return image;
+}
+
+/**
+ * eom_list_store_get_pos_by_iter:
+ * @store: An #EomListStore.
+ * @iter: A #GtkTreeIter pointing to an image in @store.
+ *
+ * Gets the position of the image pointed by @iter.
+ *
+ * Returns: The position of the image pointed by @iter.
+ **/
+gint
+eom_list_store_get_pos_by_iter (EomListStore *store,
+				GtkTreeIter *iter)
+{
+	gint *indices;
+	GtkTreePath *path;
+	gint pos;
+
+	path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+	indices = gtk_tree_path_get_indices (path);
+	pos = indices [0];
+	gtk_tree_path_free (path);
+
+	return pos;
+}
+
+/**
+ * eom_list_store_length:
+ * @store: An #EomListStore.
+ *
+ * Returns the number of images in the store.
+ *
+ * Returns: The number of images in @store.
+ **/
+gint
+eom_list_store_length (EomListStore *store)
+{
+	g_return_val_if_fail (EOM_IS_LIST_STORE (store), -1);
+
+	return gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
+}
+
+/**
+ * eom_list_store_get_initial_pos:
+ * @store: An #EomListStore.
+ *
+ * Gets the position of the #EomImage that should be loaded first.
+ * If not set, it returns -1.
+ *
+ * Returns: the position of the image to be loaded first or -1.
+ *
+ **/
+gint
+eom_list_store_get_initial_pos (EomListStore *store)
+{
+	g_return_val_if_fail (EOM_IS_LIST_STORE (store), -1);
+
+	return store->priv->initial_image;
+}
+
+static void
+eom_list_store_remove_thumbnail_job (EomListStore *store,
+				     GtkTreeIter *iter)
+{
+	EomJob *job;
+
+	gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+			    EOM_LIST_STORE_EOM_JOB, &job,
+			    -1);
+
+	if (job != NULL) {
+		g_mutex_lock (&store->priv->mutex);
+		eom_job_queue_remove_job (job);
+		gtk_list_store_set (GTK_LIST_STORE (store), iter,
+				    EOM_LIST_STORE_EOM_JOB, NULL,
+				    -1);
+		g_mutex_unlock (&store->priv->mutex);
+	}
+
+
+}
+
+static void
+eom_list_store_add_thumbnail_job (EomListStore *store, GtkTreeIter *iter)
+{
+	EomImage *image;
+	EomJob *job;
+
+	gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+			    EOM_LIST_STORE_EOM_IMAGE, &image,
+			    EOM_LIST_STORE_EOM_JOB, &job,
+			    -1);
+
+	if (job != NULL) {
+		g_object_unref (image);
+		return;
+	}
+
+	job = eom_job_thumbnail_new (image);
+
+	g_signal_connect (job,
+			  "finished",
+			  G_CALLBACK (eom_job_thumbnail_cb),
+			  store);
+
+	g_mutex_lock (&store->priv->mutex);
+	gtk_list_store_set (GTK_LIST_STORE (store), iter,
+			    EOM_LIST_STORE_EOM_JOB, job,
+			    -1);
+	eom_job_queue_add_job (job);
+	g_mutex_unlock (&store->priv->mutex);
+	g_object_unref (job);
+	g_object_unref (image);
+}
+
+/**
+ * eom_list_store_thumbnail_set:
+ * @store: An #EomListStore.
+ * @iter: A #GtkTreeIter pointing to an image in @store.
+ *
+ * Sets the thumbnail for the image pointed by @iter.
+ *
+ **/
+void
+eom_list_store_thumbnail_set (EomListStore *store,
+			      GtkTreeIter *iter)
+{
+	gboolean thumb_set = FALSE;
+
+	gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+			    EOM_LIST_STORE_THUMB_SET, &thumb_set,
+			    -1);
+
+	if (thumb_set) {
+		return;
+	}
+
+	eom_list_store_add_thumbnail_job (store, iter);
+}
+
+/**
+ * eom_list_store_thumbnail_unset:
+ * @store: An #EomListStore.
+ * @iter: A #GtkTreeIter pointing to an image in @store.
+ *
+ * Unsets the thumbnail for the image pointed by @iter, changing
+ * it to a "busy" icon.
+ *
+ **/
+void
+eom_list_store_thumbnail_unset (EomListStore *store,
+				GtkTreeIter *iter)
+{
+	EomImage *image;
+
+	eom_list_store_remove_thumbnail_job (store, iter);
+
+	gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+			    EOM_LIST_STORE_EOM_IMAGE, &image,
+			    -1);
+	eom_image_set_thumbnail (image, NULL);
+	g_object_unref (image);
+
+	gtk_list_store_set (GTK_LIST_STORE (store), iter,
+			    EOM_LIST_STORE_THUMBNAIL, store->priv->busy_image,
+			    EOM_LIST_STORE_THUMB_SET, FALSE,
+			    -1);
+}
+
+/**
+ * eom_list_store_thumbnail_refresh:
+ * @store: An #EomListStore.
+ * @iter: A #GtkTreeIter pointing to an image in @store.
+ *
+ * Refreshes the thumbnail for the image pointed by @iter.
+ *
+ **/
+void
+eom_list_store_thumbnail_refresh (EomListStore *store,
+				  GtkTreeIter *iter)
+{
+	eom_list_store_remove_thumbnail_job (store, iter);
+	eom_list_store_add_thumbnail_job (store, iter);
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/13.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/13.html new file mode 100644 index 0000000..8a2c3e3 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/13.html @@ -0,0 +1,1534 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
/* Eye Of Mate - EOM Metadata Details
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <lucasr@gnome.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eom-metadata-details.h"
+#include "eom-util.h"
+
+#if HAVE_EXIF
+#include <libexif/exif-entry.h>
+#include <libexif/exif-utils.h>
+#endif
+#if HAVE_EXEMPI
+#include <exempi/xmp.h>
+#include <exempi/xmpconsts.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <string.h>
+#include <math.h>
+
+typedef enum {
+    EXIF_CATEGORY_CAMERA,
+    EXIF_CATEGORY_IMAGE_DATA,
+    EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS,
+    EXIF_CATEGORY_GPS_DATA,
+    EXIF_CATEGORY_MAKER_NOTE,
+    EXIF_CATEGORY_OTHER,
+#ifdef HAVE_EXEMPI
+    XMP_CATEGORY_EXIF,
+    XMP_CATEGORY_IPTC,
+    XMP_CATEGORY_RIGHTS,
+    XMP_CATEGORY_OTHER
+#endif
+} MetadataCategory;
+
+typedef struct {
+    char *label;
+    char *path;
+} ExifCategoryInfo;
+
+static ExifCategoryInfo exif_categories[] = {
+    { N_("Camera"),                  "0" },
+    { N_("Image Data"),              "1" },
+    { N_("Image Taking Conditions"), "2" },
+    { N_("GPS Data"),                "3" },
+    { N_("Maker Note"),              "4" },
+    { N_("Other"),                   "5" },
+#ifdef HAVE_EXEMPI
+    { N_("XMP Exif"),                "6" },
+    { N_("XMP IPTC"),                "7" },
+    { N_("XMP Rights Management"),   "8" },
+    { N_("XMP Other"),               "9" },
+#endif
+    { NULL, NULL }
+};
+
+typedef struct {
+    int id;<--- struct member 'ExifTagCategory::id' is never used.
+    MetadataCategory category;
+} ExifTagCategory;
+
+#ifdef HAVE_EXIF
+static ExifTagCategory exif_tag_category_map[] = {
+    { EXIF_TAG_INTEROPERABILITY_INDEX,       EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_INTEROPERABILITY_VERSION,     EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_IMAGE_WIDTH,                  EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_IMAGE_LENGTH,                 EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_BITS_PER_SAMPLE,              EXIF_CATEGORY_CAMERA },
+    { EXIF_TAG_COMPRESSION,                  EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_PHOTOMETRIC_INTERPRETATION,   EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_FILL_ORDER,                   EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_DOCUMENT_NAME,                EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_IMAGE_DESCRIPTION,            EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_MAKE,                         EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_MODEL,                        EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_STRIP_OFFSETS,                EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_ORIENTATION,                  EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_SAMPLES_PER_PIXEL,            EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_ROWS_PER_STRIP,               EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_STRIP_BYTE_COUNTS,            EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_X_RESOLUTION,                 EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_Y_RESOLUTION,                 EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_PLANAR_CONFIGURATION,         EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_RESOLUTION_UNIT,              EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_TRANSFER_FUNCTION,            EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_SOFTWARE,                     EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_DATE_TIME,                    EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_ARTIST,                       EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_WHITE_POINT,                  EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_PRIMARY_CHROMATICITIES,       EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_TRANSFER_RANGE,               EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_JPEG_PROC,                    EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_JPEG_INTERCHANGE_FORMAT,      EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, },
+    { EXIF_TAG_YCBCR_COEFFICIENTS,           EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_YCBCR_SUB_SAMPLING,           EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_YCBCR_POSITIONING,            EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_REFERENCE_BLACK_WHITE,        EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_RELATED_IMAGE_FILE_FORMAT,    EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_RELATED_IMAGE_WIDTH,          EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_RELATED_IMAGE_LENGTH,         EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_CFA_REPEAT_PATTERN_DIM,       EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_CFA_PATTERN,                  EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_BATTERY_LEVEL,                EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_COPYRIGHT,                    EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_EXPOSURE_TIME,                EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_FNUMBER,                      EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_IPTC_NAA,                     EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_EXIF_IFD_POINTER,             EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_INTER_COLOR_PROFILE,          EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_EXPOSURE_PROGRAM,             EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_SPECTRAL_SENSITIVITY,         EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_GPS_INFO_IFD_POINTER,         EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_ISO_SPEED_RATINGS,            EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_OECF,                         EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_EXIF_VERSION,                 EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_DATE_TIME_ORIGINAL,           EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_DATE_TIME_DIGITIZED,          EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_COMPONENTS_CONFIGURATION,     EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_COMPRESSED_BITS_PER_PIXEL,    EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_SHUTTER_SPEED_VALUE,          EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_APERTURE_VALUE,               EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_BRIGHTNESS_VALUE,             EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_EXPOSURE_BIAS_VALUE,          EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_MAX_APERTURE_VALUE,           EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_SUBJECT_DISTANCE,             EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_METERING_MODE,                EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_LIGHT_SOURCE,                 EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_FLASH,                        EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_FOCAL_LENGTH,                 EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_SUBJECT_AREA,                 EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_MAKER_NOTE,                   EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_USER_COMMENT,                 EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_SUBSEC_TIME,                  EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_SUB_SEC_TIME_ORIGINAL,        EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_SUB_SEC_TIME_DIGITIZED,       EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_FLASH_PIX_VERSION,            EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_COLOR_SPACE,                  EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_PIXEL_X_DIMENSION,            EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_PIXEL_Y_DIMENSION,            EXIF_CATEGORY_IMAGE_DATA},
+    { EXIF_TAG_RELATED_SOUND_FILE,           EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_INTEROPERABILITY_IFD_POINTER, EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_FLASH_ENERGY,                 EXIF_CATEGORY_OTHER },
+    { EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE,   EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_FOCAL_PLANE_X_RESOLUTION,     EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION,     EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT,  EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_SUBJECT_LOCATION,             EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_EXPOSURE_INDEX,               EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_SENSING_METHOD,               EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_FILE_SOURCE,                  EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_SCENE_TYPE,                   EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_NEW_CFA_PATTERN,              EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_CUSTOM_RENDERED,              EXIF_CATEGORY_OTHER},
+    { EXIF_TAG_EXPOSURE_MODE,                EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_WHITE_BALANCE,                EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_DIGITAL_ZOOM_RATIO,           EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM,    EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_SCENE_CAPTURE_TYPE,           EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_GAIN_CONTROL,                 EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_CONTRAST,                     EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_SATURATION,                   EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_SHARPNESS,                    EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_DEVICE_SETTING_DESCRIPTION,   EXIF_CATEGORY_CAMERA},
+    { EXIF_TAG_SUBJECT_DISTANCE_RANGE,       EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+    { EXIF_TAG_IMAGE_UNIQUE_ID,              EXIF_CATEGORY_IMAGE_DATA},
+    { -1, -1 }
+};
+#endif
+
+#define MODEL_COLUMN_ATTRIBUTE 0
+#define MODEL_COLUMN_VALUE     1
+
+struct _EomMetadataDetailsPrivate {
+    GtkTreeModel *model;
+
+    GHashTable   *id_path_hash;
+    GHashTable   *id_path_hash_mnote;
+};
+
+static char*  set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value);
+
+static void eom_metadata_details_reset (EomMetadataDetails *exif_details);
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomMetadataDetails, eom_metadata_details, GTK_TYPE_TREE_VIEW)
+
+static void
+eom_metadata_details_dispose (GObject *object)
+{
+    EomMetadataDetailsPrivate *priv;
+
+    priv = EOM_METADATA_DETAILS (object)->priv;
+
+    if (priv->model) {
+        g_object_unref (priv->model);
+        priv->model = NULL;
+    }
+
+    if (priv->id_path_hash) {
+        g_hash_table_destroy (priv->id_path_hash);
+        priv->id_path_hash = NULL;
+    }
+
+    if (priv->id_path_hash_mnote) {
+        g_hash_table_destroy (priv->id_path_hash_mnote);
+        priv->id_path_hash_mnote = NULL;
+    }
+    G_OBJECT_CLASS (eom_metadata_details_parent_class)->dispose (object);
+}
+
+static void
+eom_metadata_details_init (EomMetadataDetails *details)
+{
+    EomMetadataDetailsPrivate *priv;
+    GtkTreeViewColumn *column;
+    GtkCellRenderer *cell;
+
+    details->priv = eom_metadata_details_get_instance_private (details);
+
+    priv = details->priv;
+
+    priv->model = GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING));
+    priv->id_path_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+    priv->id_path_hash_mnote = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+
+    /* Tag name column */
+    cell = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes (_("Tag"), cell,
+                                                       "text", MODEL_COLUMN_ATTRIBUTE,
+                                                       NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (details), column);
+
+    /* Value column */
+    cell = gtk_cell_renderer_text_new ();
+    g_object_set (cell,
+                  "editable", TRUE,
+                  NULL);
+    column = gtk_tree_view_column_new_with_attributes (_("Value"), cell,
+                                                       "text", MODEL_COLUMN_VALUE,
+                                                       NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (details), column);
+
+    eom_metadata_details_reset (details);
+
+    gtk_tree_view_set_model (GTK_TREE_VIEW (details),
+                             GTK_TREE_MODEL (priv->model));
+}
+
+static void
+eom_metadata_details_class_init (EomMetadataDetailsClass *klass)
+{
+    GObjectClass *object_class = (GObjectClass*) klass;
+
+    object_class->dispose = eom_metadata_details_dispose;
+}
+
+#ifdef HAVE_EXIF
+static MetadataCategory
+get_exif_category (ExifEntry *entry)
+{
+    MetadataCategory cat = EXIF_CATEGORY_OTHER;
+    int i;
+
+    /* Some GPS tag IDs overlap with other ones, so check the IFD */
+    if (exif_entry_get_ifd (entry) == EXIF_IFD_GPS) {
+        return EXIF_CATEGORY_GPS_DATA;
+    }
+
+    for (i = 0; exif_tag_category_map [i].id != -1; i++) {
+        if (exif_tag_category_map[i].id == (int) entry->tag) {
+            cat = exif_tag_category_map[i].category;
+            break;
+        }
+    }
+
+    return cat;
+}
+#endif
+
+static char*
+set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value)
+{
+    GtkTreeIter iter;
+    gchar *utf_attribute = NULL;
+    gchar *utf_value = NULL;
+    gboolean iter_valid = FALSE;
+
+    if (!attribute) return NULL;
+
+    if (path != NULL) {
+        iter_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path);
+    }
+
+    if (!iter_valid) {
+        GtkTreePath *tree_path;
+        GtkTreeIter parent_iter;
+        gboolean parent_valid = FALSE;
+
+        if (parent != NULL) {
+            parent_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store),
+                                                                &parent_iter,
+                                                                parent);
+        }
+
+        gtk_tree_store_append (store, &iter, parent_valid ? &parent_iter : NULL);
+
+        if (path == NULL) {
+            tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
+
+            if (tree_path != NULL) {
+                path = gtk_tree_path_to_string (tree_path);
+                gtk_tree_path_free (tree_path);
+            }
+        }
+    }
+
+    utf_attribute = eom_util_make_valid_utf8 (attribute);
+
+    gtk_tree_store_set (store, &iter, MODEL_COLUMN_ATTRIBUTE, utf_attribute, -1);
+    g_free (utf_attribute);
+
+    if (value != NULL) {
+        utf_value = eom_util_make_valid_utf8 (value);
+        gtk_tree_store_set (store, &iter, MODEL_COLUMN_VALUE, utf_value, -1);
+        g_free (utf_value);
+    }
+
+    return path;
+}
+
+#ifdef HAVE_EXIF
+
+static const char *
+eom_exif_entry_get_value (ExifEntry    *e,
+                          char         *buf,
+                          guint         n_buf)
+{
+    ExifByteOrder bo;
+
+    /* For now we only want to reformat some GPS values */
+    if (G_LIKELY (exif_entry_get_ifd (e) != EXIF_IFD_GPS))
+        return exif_entry_get_value (e, buf, n_buf);
+
+    bo = exif_data_get_byte_order (e->parent->parent);
+
+    /* Cast to number to avoid warnings about values not in enumeration */
+    switch ((guint16) e->tag) {
+        case EXIF_TAG_GPS_LATITUDE:
+        case EXIF_TAG_GPS_LONGITUDE:
+        {
+            gsize rational_size;
+            ExifRational r;
+            gfloat h = 0., m = 0., s = 0.;
+
+
+            rational_size = exif_format_get_size (EXIF_FORMAT_RATIONAL);
+            if (G_UNLIKELY (e->components != 3 ||
+                e->format != EXIF_FORMAT_RATIONAL))
+                return exif_entry_get_value (e, buf, n_buf);
+
+            r = exif_get_rational (e->data, bo);
+            if (r.denominator != 0)
+                h = (gfloat)r.numerator / r.denominator;
+
+            r = exif_get_rational (e->data + rational_size, bo);
+			if (r.denominator != 0) {
+				if (r.numerator != 0) {
+					m = (gfloat)r.numerator /
+					    (gfloat)r.denominator;
+				} else {
+					double integ;
+
+					m = (gfloat)(modf (h, &integ) * 60.0);
+					h = (gfloat) integ;
+				}
+			}
+
+            r = exif_get_rational (e->data + (2 * rational_size),
+                           bo);
+			if (r.denominator != 0) {
+				if (r.numerator != 0) {
+					s = (gfloat)r.numerator /
+					    (gfloat)r.denominator;
+				} else {
+					double integ;
+
+					s = (gfloat)(modf (m, &integ) * 60.0);
+					m = (gfloat) integ;
+				}
+			}
+
+			if (s != 0.0) {
+                g_snprintf (buf, n_buf,
+                        "%.0f° %.0f' %.2f\"",
+                        h, m, s);
+            } else {
+                g_snprintf (buf, n_buf,
+                        "%.0f° %.2f'",
+                        h, m);
+            }
+
+            break;
+        }
+        case EXIF_TAG_GPS_LATITUDE_REF:
+        case EXIF_TAG_GPS_LONGITUDE_REF:
+        {
+            if (G_UNLIKELY (e->components != 2 ||
+                e->format != EXIF_FORMAT_ASCII))
+                return exif_entry_get_value (e, buf, n_buf);
+
+            switch (e->data[0]) {
+            case 'N':
+                g_snprintf (buf, n_buf, "%s", _("North"));
+                break;
+            case 'E':
+                g_snprintf (buf, n_buf, "%s", _("East"));
+                break;
+            case 'W':
+                g_snprintf (buf, n_buf, "%s", _("West"));
+                break;
+            case 'S':
+                g_snprintf (buf, n_buf, "%s", _("South"));
+                break;
+            default:
+                return exif_entry_get_value (e, buf, n_buf);
+                break;
+            }
+            break;
+        }
+        default:
+            return exif_entry_get_value (e, buf, n_buf);
+            break;
+    }
+
+    return buf;
+}
+
+static void
+exif_entry_cb (ExifEntry *entry, gpointer data)
+{
+    GtkTreeStore *store;
+    EomMetadataDetails *view;
+    EomMetadataDetailsPrivate *priv;
+    MetadataCategory cat;
+    ExifIfd ifd = exif_entry_get_ifd (entry);
+    char *path;
+    char b[1024];
+    const gint key = ifd << 16 | entry->tag;
+
+    /* This should optimize away if comparision is correct */
+    g_warn_if_fail (EXIF_IFD_COUNT <= G_MAXUINT16);
+
+    view = EOM_METADATA_DETAILS (data);
+    priv = view->priv;
+
+    store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
+
+    /* Take the tag's IFD into account when caching their GtkTreePaths.
+     * That should fix key collisions for tags that have the same number
+     * but are stored in different IFDs. Exif tag numbers are 16-bit
+     * values so we should be able to set the high word to the IFD number.
+     */
+    path = g_hash_table_lookup (priv->id_path_hash, GINT_TO_POINTER (key));
+
+    if (path != NULL) {
+        set_row_data (store,
+                      path,
+                      NULL,
+                      exif_tag_get_name_in_ifd (entry->tag, ifd),
+                      eom_exif_entry_get_value (entry, b, sizeof(b)));
+    } else {
+
+        ExifMnoteData *mnote = (entry->tag == EXIF_TAG_MAKER_NOTE ?
+                                exif_data_get_mnote_data (entry->parent->parent) : NULL);
+
+        if (mnote) {
+            // Supported MakerNote Found
+            unsigned int i, c = exif_mnote_data_count (mnote);
+
+            for (i = 0; i < c; i++) {
+                path = g_hash_table_lookup (priv->id_path_hash_mnote, GINT_TO_POINTER (i));
+                if (path != NULL) {
+                    set_row_data (store, path, NULL,
+                                  exif_mnote_data_get_title (mnote, i),
+                                  exif_mnote_data_get_value (mnote, i, b, sizeof(b)));
+                } else {
+                    path = set_row_data (store,
+                                         NULL,
+                                         exif_categories[EXIF_CATEGORY_MAKER_NOTE].path,
+                                         exif_mnote_data_get_title (mnote, i),
+                                         exif_mnote_data_get_value (mnote, i, b, sizeof(b)));
+                    g_hash_table_insert (priv->id_path_hash_mnote, GINT_TO_POINTER (i), path);
+                }
+            }
+        } else {
+            cat = get_exif_category (entry);
+
+            path = set_row_data (store,
+                                 NULL,
+                                 exif_categories[cat].path,
+                                 exif_tag_get_name_in_ifd (entry->tag, ifd),
+                                 eom_exif_entry_get_value (entry, b,
+                                 sizeof(b)));
+
+            g_hash_table_insert (priv->id_path_hash,
+                                 GINT_TO_POINTER (key),
+                                 path);
+        }
+    }
+}
+#endif
+
+#ifdef HAVE_EXIF
+static void
+exif_content_cb (ExifContent *content, gpointer data)
+{
+    exif_content_foreach_entry (content, exif_entry_cb, data);
+}
+#endif
+
+GtkWidget *
+eom_metadata_details_new (void)
+{
+    GObject *object;
+
+    object = g_object_new (EOM_TYPE_METADATA_DETAILS, NULL);
+
+    return GTK_WIDGET (object);
+}
+
+static void
+eom_metadata_details_reset (EomMetadataDetails *details)
+{
+    EomMetadataDetailsPrivate *priv = details->priv;
+    int i;
+
+    gtk_tree_store_clear (GTK_TREE_STORE (priv->model));
+
+    g_hash_table_remove_all (priv->id_path_hash);
+    g_hash_table_remove_all (priv->id_path_hash_mnote);
+
+    for (i = 0; exif_categories [i].label != NULL; i++) {
+        char *translated_string;
+
+        translated_string = gettext (exif_categories[i].label);
+
+        set_row_data (GTK_TREE_STORE (priv->model),
+                      exif_categories[i].path,
+                      NULL,
+                      translated_string,
+                      NULL);
+    }
+}
+
+#ifdef HAVE_EXIF
+void
+eom_metadata_details_update (EomMetadataDetails *details, ExifData *data)
+{
+    g_return_if_fail (EOM_IS_METADATA_DETAILS (details));
+
+    eom_metadata_details_reset (details);
+    if (data) {
+        exif_data_foreach_content (data, exif_content_cb, details);
+    }
+}
+#endif /* HAVE_EXIF */
+
+#ifdef HAVE_EXEMPI
+typedef struct {
+    const char *id;
+    MetadataCategory category;
+} XmpNsCategory;
+
+static XmpNsCategory xmp_ns_category_map[] = {
+    { NS_EXIF,                  XMP_CATEGORY_EXIF},
+    { NS_TIFF,                  XMP_CATEGORY_EXIF},
+    { NS_XAP,                   XMP_CATEGORY_EXIF},
+    { NS_XAP_RIGHTS,            XMP_CATEGORY_RIGHTS},
+    { NS_EXIF_AUX,              XMP_CATEGORY_EXIF},
+    { NS_DC,                    XMP_CATEGORY_IPTC},
+    { NS_IPTC4XMP,              XMP_CATEGORY_IPTC},
+    { NS_CC,                    XMP_CATEGORY_RIGHTS},
+    { NULL, -1}
+};
+
+static MetadataCategory
+get_xmp_category (XmpStringPtr schema)
+{
+    MetadataCategory cat = XMP_CATEGORY_OTHER;
+    const char *s = xmp_string_cstr(schema);
+    int i;
+
+    for (i = 0; xmp_ns_category_map[i].id != NULL; i++) {
+        if (strcmp (xmp_ns_category_map[i].id, s) == 0) {
+            cat = xmp_ns_category_map[i].category;
+            break;
+        }
+    }
+
+    return cat;
+}
+
+static void
+xmp_entry_insert (EomMetadataDetails *view, XmpStringPtr xmp_schema,
+                  XmpStringPtr xmp_path, XmpStringPtr xmp_prop)
+{
+    GtkTreeStore *store;
+    EomMetadataDetailsPrivate *priv;
+    MetadataCategory cat;
+    char *path;
+    gchar *key;
+
+    priv = view->priv;
+
+    key = g_strconcat (xmp_string_cstr (xmp_schema), ":",
+                       xmp_string_cstr (xmp_path), NULL);
+
+    store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
+
+    path = g_hash_table_lookup (priv->id_path_hash, key);
+
+    if (path != NULL) {
+        set_row_data (store, path, NULL,
+                      xmp_string_cstr (xmp_path),
+                      xmp_string_cstr (xmp_prop));
+
+        g_free(key);
+    }
+    else {
+        cat = get_xmp_category (xmp_schema);
+
+        path = set_row_data (store, NULL, exif_categories[cat].path,
+                             xmp_string_cstr(xmp_path),
+                             xmp_string_cstr(xmp_prop));
+
+        g_hash_table_insert (priv->id_path_hash, key, path);
+    }
+}
+
+void
+eom_metadata_details_xmp_update (EomMetadataDetails *view, XmpPtr data)
+{
+    g_return_if_fail (EOM_IS_METADATA_DETAILS (view));
+
+    if (data) {
+        XmpIteratorPtr iter = xmp_iterator_new(data, NULL, NULL, XMP_ITER_JUSTLEAFNODES);
+        XmpStringPtr the_schema = xmp_string_new ();
+        XmpStringPtr the_path = xmp_string_new ();
+        XmpStringPtr the_prop = xmp_string_new ();
+
+        while (xmp_iterator_next (iter, the_schema, the_path, the_prop, NULL)) {
+            xmp_entry_insert (view, the_schema, the_path, the_prop);
+        }
+
+        xmp_string_free (the_prop);
+        xmp_string_free (the_path);
+        xmp_string_free (the_schema);
+        xmp_iterator_free (iter);
+    }
+}
+#endif
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/14.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/14.html new file mode 100644 index 0000000..3e599c7 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/14.html @@ -0,0 +1,414 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
/* Eye Of MATE -- Metadata Reader Interface
+ *
+ * Copyright (C) 2008 The Free Software Foundation
+ *
+ * Author: Felix Riemann <friemann@svn.gnome.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eom-metadata-reader.h"
+#include "eom-metadata-reader-jpg.h"
+#include "eom-metadata-reader-png.h"
+#include "eom-debug.h"
+
+G_DEFINE_INTERFACE (EomMetadataReader, eom_metadata_reader, G_TYPE_INVALID)<--- There is an unknown macro here somewhere. Configuration is required. If G_DEFINE_INTERFACE is a macro then please configure it.
+
+EomMetadataReader*
+eom_metadata_reader_new (EomMetadataFileType type)
+{
+	EomMetadataReader *emr;
+
+	switch (type) {
+	case EOM_METADATA_JPEG:
+		emr = EOM_METADATA_READER (g_object_new (EOM_TYPE_METADATA_READER_JPG, NULL));
+		break;
+	case EOM_METADATA_PNG:
+		emr = EOM_METADATA_READER (g_object_new (EOM_TYPE_METADATA_READER_PNG, NULL));
+		break;
+	default:
+		emr = NULL;
+		break;
+	}
+
+	return emr;
+}
+
+gboolean
+eom_metadata_reader_finished (EomMetadataReader *emr)
+{
+	g_return_val_if_fail (EOM_IS_METADATA_READER (emr), TRUE);
+
+	return EOM_METADATA_READER_GET_INTERFACE (emr)->finished (emr);
+}
+
+
+void
+eom_metadata_reader_consume (EomMetadataReader *emr, const guchar *buf, guint len)
+{
+	EOM_METADATA_READER_GET_INTERFACE (emr)->consume (emr, buf, len);
+}
+
+/* Returns the raw exif data. NOTE: The caller of this function becomes
+ * the new owner of this piece of memory and is responsible for freeing it!
+ */
+void
+eom_metadata_reader_get_exif_chunk (EomMetadataReader *emr, guchar **data, guint *len)
+{
+	g_return_if_fail (data != NULL && len != NULL);
+
+	EOM_METADATA_READER_GET_INTERFACE (emr)->get_raw_exif (emr, data, len);
+}
+
+#ifdef HAVE_EXIF
+ExifData*
+eom_metadata_reader_get_exif_data (EomMetadataReader *emr)
+{
+	return EOM_METADATA_READER_GET_INTERFACE (emr)->get_exif_data (emr);
+}
+#endif
+
+#ifdef HAVE_EXEMPI
+XmpPtr
+eom_metadata_reader_get_xmp_data (EomMetadataReader *emr)
+{
+	return EOM_METADATA_READER_GET_INTERFACE (emr)->get_xmp_ptr (emr);
+}
+#endif
+
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+cmsHPROFILE
+eom_metadata_reader_get_icc_profile (EomMetadataReader *emr)
+{
+	return EOM_METADATA_READER_GET_INTERFACE (emr)->get_icc_profile (emr);
+}
+#endif
+
+/* Default vfunc that simply clears the output if not overriden by the
+   implementing class. This mimics the old behavour of get_exif_chunk(). */
+static void
+_eom_metadata_reader_default_get_raw_exif (EomMetadataReader *emr,
+					   guchar **data, guint *length)
+{
+	g_return_if_fail (data != NULL && length != NULL);
+	*data = NULL;
+	*length = 0;
+}
+
+/* Default vfunc that simply returns NULL if not overriden by the implementing
+   class. Mimics the old fallback behaviour of the getter functions. */
+static gpointer
+_eom_metadata_reader_default_get_null (EomMetadataReader *emr)
+{
+	return NULL;
+}
+static void
+eom_metadata_reader_default_init (EomMetadataReaderInterface *iface)
+{
+	/* consume and finished are required to be implemented */
+	/* Not-implemented funcs return NULL by default */
+	iface->get_raw_exif = _eom_metadata_reader_default_get_raw_exif;
+	iface->get_exif_data = _eom_metadata_reader_default_get_null;
+	iface->get_icc_profile = _eom_metadata_reader_default_get_null;
+	iface->get_xmp_ptr = _eom_metadata_reader_default_get_null;
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/15.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/15.html new file mode 100644 index 0000000..4bcb98d --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/15.html @@ -0,0 +1,2274 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
/* Eye Of MATE -- Print Dialog Custom Widget
+ *
+ * Copyright (C) 2006-2007 The Free Software Foundation
+ *
+ * Author: Claudio Saavedra <csaavedra@alumnos.utalca.cl>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+#include <gtk/gtkunixprint.h>
+
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+#include <langinfo.h>
+#endif
+
+#include "eom-print-image-setup.h"
+#include "eom-print-preview.h"
+
+/**
+ * SECTION:
+ * @Title: Printing Custom Widget
+ * @Short_Description: a custom widget to setup image prints.
+ * @Stability_Level: Internal
+ * @See_Also: #EomPrintPreview
+ *
+ * This widget is to be used as the custom widget in a #GtkPrintUnixDialog in
+ * EOM. Through it, you can set the position and scaling of a image
+ * interactively.
+ */
+
+struct _EomPrintImageSetupPrivate {
+	GtkWidget *left;
+	GtkWidget *right;
+	GtkWidget *top;
+	GtkWidget *bottom;
+
+	GtkWidget *center;
+
+	GtkWidget *width;
+	GtkWidget *height;
+
+	GtkWidget *scaling;
+	GtkWidget *unit;
+
+	GtkUnit current_unit;
+
+	EomImage *image;
+	GtkPageSetup *page_setup;
+
+	GtkWidget *preview;
+};
+
+enum {
+	PROP_0,
+	PROP_IMAGE,
+	PROP_PAGE_SETUP
+};
+
+enum {
+	CENTER_NONE,
+	CENTER_HORIZONTAL,
+	CENTER_VERTICAL,
+	CENTER_BOTH
+};
+
+enum {
+	CHANGE_HORIZ,
+	CHANGE_VERT
+};
+
+enum {
+	UNIT_INCH,
+	UNIT_MM
+};
+
+#define FACTOR_INCH_TO_MM 25.4
+#define FACTOR_INCH_TO_PIXEL 72.
+#define FACTOR_MM_TO_INCH 0.03937007874015748
+#define FACTOR_MM_TO_PIXEL 2.834645669
+
+static void eom_print_image_setup_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void eom_print_image_setup_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static void on_left_value_changed   (GtkSpinButton *spinbutton, gpointer user_data);
+static void on_right_value_changed  (GtkSpinButton *spinbutton, gpointer user_data);
+static void on_top_value_changed    (GtkSpinButton *spinbutton, gpointer user_data);
+static void on_bottom_value_changed (GtkSpinButton *spinbutton, gpointer user_data);
+
+static void on_width_value_changed  (GtkSpinButton *spinbutton, gpointer user_data);
+static void on_height_value_changed (GtkSpinButton *spinbutton, gpointer user_data);
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomPrintImageSetup, eom_print_image_setup, GTK_TYPE_GRID);
+
+static void
+block_handlers (EomPrintImageSetup *setup)
+{
+	EomPrintImageSetupPrivate *priv = setup->priv;
+
+	g_signal_handlers_block_by_func (priv->left, on_left_value_changed, setup);
+	g_signal_handlers_block_by_func (priv->right, on_right_value_changed, setup);
+	g_signal_handlers_block_by_func (priv->width, on_width_value_changed, setup);
+	g_signal_handlers_block_by_func (priv->top, on_top_value_changed, setup);
+	g_signal_handlers_block_by_func (priv->bottom, on_bottom_value_changed, setup);
+	g_signal_handlers_block_by_func (priv->height, on_height_value_changed, setup);
+}
+
+static void
+unblock_handlers (EomPrintImageSetup *setup)
+{
+	EomPrintImageSetupPrivate *priv = setup->priv;
+
+	g_signal_handlers_unblock_by_func (priv->left, on_left_value_changed, setup);
+	g_signal_handlers_unblock_by_func (priv->right, on_right_value_changed, setup);
+	g_signal_handlers_unblock_by_func (priv->width, on_width_value_changed, setup);
+	g_signal_handlers_unblock_by_func (priv->top, on_top_value_changed, setup);
+	g_signal_handlers_unblock_by_func (priv->bottom, on_bottom_value_changed, setup);
+	g_signal_handlers_unblock_by_func (priv->height, on_height_value_changed, setup);
+}
+
+static gdouble
+get_scale_to_px_factor (EomPrintImageSetup *setup)
+{
+	gdouble factor = 0.;
+
+	switch (setup->priv->current_unit) {
+	case GTK_UNIT_MM:
+		factor = FACTOR_MM_TO_PIXEL;
+		break;
+	case GTK_UNIT_INCH:
+		factor = FACTOR_INCH_TO_PIXEL;
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	return factor;
+}
+
+static gdouble
+get_max_percentage (EomPrintImageSetup *setup)
+{
+	EomPrintImageSetupPrivate *priv = setup->priv;
+	gdouble p_width, p_height;
+	gdouble width, height;
+	gint pix_width, pix_height;
+	gdouble perc;
+
+	p_width = gtk_page_setup_get_page_width (priv->page_setup, GTK_UNIT_INCH);
+	p_height = gtk_page_setup_get_page_height (priv->page_setup, GTK_UNIT_INCH);
+
+	eom_image_get_size (priv->image, &pix_width, &pix_height);
+
+	width  = (gdouble)pix_width/FACTOR_INCH_TO_PIXEL;
+	height = (gdouble)pix_height/FACTOR_INCH_TO_PIXEL;
+
+	if (p_width > width && p_height > height) {
+		perc = 1.;
+	} else {
+		perc = MIN (p_width/width, p_height/height);
+	}
+
+	return perc;
+}
+
+static void
+center (gdouble page_width,
+	gdouble width,
+	GtkSpinButton *s_left,
+	GtkSpinButton *s_right)
+{
+	gdouble left, right;
+
+	left = (page_width - width)/2;
+	right = page_width - left - width;
+	gtk_spin_button_set_value (s_left, left);
+	gtk_spin_button_set_value (s_right, right);
+}
+
+static void
+on_center_changed (GtkComboBox *combobox,
+		   gpointer user_data)
+{
+	EomPrintImageSetup *setup;
+	EomPrintImageSetupPrivate *priv;
+	gint active;
+
+	setup = EOM_PRINT_IMAGE_SETUP (user_data);
+	priv = setup->priv;
+
+	active = gtk_combo_box_get_active (combobox);
+
+	switch (active) {
+	case CENTER_HORIZONTAL:
+		center (gtk_page_setup_get_page_width (priv->page_setup,
+						       priv->current_unit),
+			gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->width)),
+			GTK_SPIN_BUTTON (priv->left),
+			GTK_SPIN_BUTTON (priv->right));
+		break;
+	case CENTER_VERTICAL:
+		center (gtk_page_setup_get_page_height (priv->page_setup,
+							priv->current_unit),
+			gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->height)),
+			GTK_SPIN_BUTTON (priv->top),
+			GTK_SPIN_BUTTON (priv->bottom));
+		break;
+	case CENTER_BOTH:
+		center (gtk_page_setup_get_page_width (priv->page_setup,
+						       priv->current_unit),
+			gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->width)),
+			GTK_SPIN_BUTTON (priv->left),
+			GTK_SPIN_BUTTON (priv->right));
+		center (gtk_page_setup_get_page_height (priv->page_setup,
+							priv->current_unit),
+			gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->height)),
+			GTK_SPIN_BUTTON (priv->top),
+			GTK_SPIN_BUTTON (priv->bottom));
+		break;
+	case CENTER_NONE:
+	default:
+		break;
+	}
+
+	gtk_combo_box_set_active (combobox, active);
+}
+
+static void
+update_image_pos_ranges (EomPrintImageSetup *setup,
+			 gdouble page_width,
+			 gdouble page_height,
+			 gdouble width,
+			 gdouble height)
+{
+	EomPrintImageSetupPrivate *priv;
+
+	priv = setup->priv;
+
+	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->left),
+				   0, page_width - width);
+	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->right),
+				   0, page_width - width);
+	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->top),
+				   0, page_height - height);
+	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->bottom),
+				   0, page_height - height);
+}
+
+static gboolean
+on_scale_changed (GtkRange     *range,
+		  gpointer      user_data)
+{
+	gdouble scale;
+	gdouble width, height;
+	gint pix_width, pix_height;
+	gdouble left, right, top, bottom;
+	gdouble page_width, page_height;
+	EomPrintImageSetupPrivate *priv;
+	EomPrintImageSetup *setup;
+	gdouble factor;
+	EomImage *image;
+
+	setup = EOM_PRINT_IMAGE_SETUP (user_data);
+	priv = setup->priv;
+
+	gtk_combo_box_set_active (GTK_COMBO_BOX (priv->center), CENTER_NONE);
+
+	image = priv->image;
+	eom_image_get_size (image, &pix_width, &pix_height);
+
+	factor = get_scale_to_px_factor (setup);
+
+	width = (gdouble)pix_width/factor;
+	height = (gdouble)pix_height/factor;
+
+	left = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->left));
+	top = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->top));
+
+	scale = CLAMP (0.01*gtk_range_get_value (range), 0, get_max_percentage (setup));
+
+ 	eom_print_preview_set_scale (EOM_PRINT_PREVIEW (priv->preview), scale);
+
+	width  *= scale;
+	height *= scale;
+
+	page_width = gtk_page_setup_get_page_width (priv->page_setup, priv->current_unit);
+	page_height = gtk_page_setup_get_page_height (priv->page_setup, priv->current_unit);
+
+	update_image_pos_ranges (setup, page_width, page_height, width, height);
+
+	right = page_width - left - width;
+	bottom = page_height - top - height;
+
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->width), width);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->height), height);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->right), right);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->bottom), bottom);
+
+	return FALSE;
+}
+
+static gchar *
+on_scale_format_value (GtkScale *scale,
+		       gdouble value)
+{
+	return g_strdup_printf ("%i%%", (gint)value);
+}
+
+static void
+position_values_changed (EomPrintImageSetup *setup,
+			 GtkWidget *w_changed,
+			 GtkWidget *w_to_update,
+			 GtkWidget *w_size,
+			 gdouble total_size,
+			 gint change)
+{
+	EomPrintImageSetupPrivate *priv;
+	gdouble changed, to_update, size;
+	gdouble pos;
+
+	priv = setup->priv;
+	size = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_size));
+	changed = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_changed));
+
+	to_update = total_size - changed - size;
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_to_update), to_update);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (priv->center), CENTER_NONE);
+
+	switch (change) {
+	case CHANGE_HORIZ:
+		pos = gtk_spin_button_get_value (GTK_SPIN_BUTTON (setup->priv->left));
+		if (setup->priv->current_unit == GTK_UNIT_MM) {
+			pos *= FACTOR_MM_TO_INCH;
+		}
+ 		eom_print_preview_set_image_position (EOM_PRINT_PREVIEW (priv->preview), pos, -1);
+		break;
+	case CHANGE_VERT:
+		pos = gtk_spin_button_get_value (GTK_SPIN_BUTTON (setup->priv->top));
+		if (setup->priv->current_unit == GTK_UNIT_MM) {
+			pos *= FACTOR_MM_TO_INCH;
+		}
+		eom_print_preview_set_image_position (EOM_PRINT_PREVIEW (priv->preview), -1, pos);
+		break;
+	}
+}
+
+static void
+on_left_value_changed (GtkSpinButton *spinbutton,
+		       gpointer       user_data)
+{
+	EomPrintImageSetup *setup;
+	EomPrintImageSetupPrivate *priv;
+
+	setup = EOM_PRINT_IMAGE_SETUP (user_data);
+	priv = setup->priv;
+
+	position_values_changed (setup,
+				 priv->left, priv->right, priv->width,
+				 gtk_page_setup_get_page_width (priv->page_setup,
+								priv->current_unit),
+				 CHANGE_HORIZ);
+}
+
+static void
+on_right_value_changed (GtkSpinButton *spinbutton,
+			gpointer       user_data)
+{
+	EomPrintImageSetupPrivate *priv;
+
+	priv = EOM_PRINT_IMAGE_SETUP (user_data)->priv;
+
+	position_values_changed (EOM_PRINT_IMAGE_SETUP (user_data),
+				 priv->right, priv->left, priv->width,
+				 gtk_page_setup_get_page_width (priv->page_setup,
+								priv->current_unit),
+				 CHANGE_HORIZ);
+}
+
+static void
+on_top_value_changed (GtkSpinButton *spinbutton,
+		      gpointer       user_data)
+{
+	EomPrintImageSetupPrivate *priv;
+
+	priv = EOM_PRINT_IMAGE_SETUP (user_data)->priv;
+
+	position_values_changed (EOM_PRINT_IMAGE_SETUP (user_data),
+				 priv->top, priv->bottom, priv->height,
+				 gtk_page_setup_get_page_height (priv->page_setup,
+								 priv->current_unit),
+				 CHANGE_VERT);
+}
+
+static void
+on_bottom_value_changed (GtkSpinButton *spinbutton,
+			 gpointer       user_data)
+{
+	EomPrintImageSetupPrivate *priv;
+
+	priv = EOM_PRINT_IMAGE_SETUP (user_data)->priv;
+
+	position_values_changed (EOM_PRINT_IMAGE_SETUP (user_data),
+				 priv->bottom, priv->top, priv->height,
+				 gtk_page_setup_get_page_height (priv->page_setup,
+								 priv->current_unit),
+				 CHANGE_VERT);
+}
+
+static void
+size_changed (EomPrintImageSetup *setup,
+	      GtkWidget *w_size_x,
+	      GtkWidget *w_size_y,
+	      GtkWidget *w_margin_x_1,
+	      GtkWidget *w_margin_x_2,
+	      GtkWidget *w_margin_y_1,
+	      GtkWidget *w_margin_y_2,
+	      gdouble page_size_x,
+	      gdouble page_size_y,
+	      gint change)
+{
+	EomPrintImageSetupPrivate *priv;
+	gdouble margin_x_1, margin_x_2;
+	gdouble margin_y_1, margin_y_2;
+	gdouble orig_size_x = -1, orig_size_y = -1, scale;
+	gdouble size_x, size_y;
+	gint pix_width, pix_height;
+	gdouble factor;
+
+	priv = setup->priv;
+
+	size_x = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_size_x));
+	margin_x_1 = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_margin_x_1));
+	margin_y_1 = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_margin_y_1));
+
+	eom_image_get_size (priv->image, &pix_width, &pix_height);
+
+	factor = get_scale_to_px_factor (setup);
+
+	switch (change) {
+	case CHANGE_HORIZ:
+		orig_size_x = (gdouble) pix_width / factor;
+		orig_size_y = (gdouble) pix_height / factor;
+		break;
+	case CHANGE_VERT:
+		orig_size_y = (gdouble) pix_width / factor;
+		orig_size_x = (gdouble) pix_height / factor;
+		break;
+	}
+
+	scale = CLAMP (size_x / orig_size_x, 0, 1);
+
+	size_y = scale * orig_size_y;
+
+	margin_x_2 = page_size_x - margin_x_1 - size_x;
+	margin_y_2 = page_size_y - margin_y_1 - size_y;
+
+ 	eom_print_preview_set_scale (EOM_PRINT_PREVIEW (priv->preview), scale);
+
+	switch (change) {
+	case CHANGE_HORIZ:
+		update_image_pos_ranges (setup, page_size_x, page_size_y, size_x, size_y);
+		break;
+	case CHANGE_VERT:
+		update_image_pos_ranges (setup, page_size_y, page_size_x, size_y, size_x);
+		break;
+	}
+
+	gtk_range_set_value (GTK_RANGE (priv->scaling), 100*scale);
+
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_margin_x_2), margin_x_2);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_size_y), size_y);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_margin_y_2), margin_y_2);
+
+	gtk_combo_box_set_active (GTK_COMBO_BOX (priv->center), CENTER_NONE);
+}
+
+static void
+on_width_value_changed (GtkSpinButton *spinbutton,
+			gpointer       user_data)
+{
+	EomPrintImageSetupPrivate *priv = EOM_PRINT_IMAGE_SETUP (user_data)->priv;
+
+	size_changed (EOM_PRINT_IMAGE_SETUP (user_data),
+		      priv->width, priv->height,
+		      priv->left, priv->right,
+		      priv->top, priv->bottom,
+		      gtk_page_setup_get_page_width (priv->page_setup,
+						     priv->current_unit),
+		      gtk_page_setup_get_page_height (priv->page_setup,
+						      priv->current_unit),
+		      CHANGE_HORIZ);
+}
+
+static void
+on_height_value_changed (GtkSpinButton *spinbutton,
+			 gpointer       user_data)
+{
+	EomPrintImageSetupPrivate *priv = EOM_PRINT_IMAGE_SETUP (user_data)->priv;
+
+	size_changed (EOM_PRINT_IMAGE_SETUP (user_data),
+		      priv->height, priv->width,
+		      priv->top, priv->bottom,
+		      priv->left, priv->right,
+		      gtk_page_setup_get_page_height (priv->page_setup,
+						     priv->current_unit),
+		      gtk_page_setup_get_page_width (priv->page_setup,
+						     priv->current_unit),
+		      CHANGE_VERT);
+}
+
+static void
+change_unit (GtkSpinButton *spinbutton,
+	     gdouble factor,
+	     gint digits,
+	     gdouble step,
+	     gdouble page)
+{
+	gdouble value;
+	gdouble range;
+
+	gtk_spin_button_get_range (spinbutton, NULL, &range);
+	range *= factor;
+
+	value = gtk_spin_button_get_value (spinbutton);
+	value *= factor;
+
+	gtk_spin_button_set_range (spinbutton, 0, range);
+	gtk_spin_button_set_value (spinbutton, value);
+	gtk_spin_button_set_digits (spinbutton, digits);
+	gtk_spin_button_set_increments  (spinbutton, step, page);
+}
+
+static void
+set_scale_unit (EomPrintImageSetup *setup,
+		GtkUnit unit)
+{
+	EomPrintImageSetupPrivate *priv = setup->priv;
+	gdouble factor;
+	gdouble step, page;
+	gint digits;
+
+	if (G_UNLIKELY (priv->current_unit == unit))
+		return;
+
+	switch (unit) {
+	case GTK_UNIT_MM:
+		factor = FACTOR_INCH_TO_MM;
+		digits = 0;
+		step = 1;
+		page = 10;
+		break;
+	case GTK_UNIT_INCH:
+		factor = FACTOR_MM_TO_INCH;
+		digits = 2;
+		step = 0.01;
+		page = 0.1;
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+ 	block_handlers (setup);
+
+	change_unit (GTK_SPIN_BUTTON (priv->width), factor, digits, step, page);
+	change_unit (GTK_SPIN_BUTTON (priv->height), factor, digits, step, page);
+	change_unit (GTK_SPIN_BUTTON (priv->left), factor, digits, step, page);
+	change_unit (GTK_SPIN_BUTTON (priv->right), factor, digits, step, page);
+	change_unit (GTK_SPIN_BUTTON (priv->top), factor, digits, step, page);
+	change_unit (GTK_SPIN_BUTTON (priv->bottom), factor, digits, step, page);
+
+ 	unblock_handlers (setup);
+
+	priv->current_unit = unit;
+}
+
+static void
+on_unit_changed (GtkComboBox *combobox,
+		 gpointer user_data)
+{
+	GtkUnit unit = GTK_UNIT_INCH;
+
+	switch (gtk_combo_box_get_active (combobox)) {
+	case UNIT_INCH:
+		unit = GTK_UNIT_INCH;
+		break;
+	case UNIT_MM:
+		unit = GTK_UNIT_MM;
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	set_scale_unit (EOM_PRINT_IMAGE_SETUP (user_data), unit);
+}
+
+static void
+on_preview_image_moved (EomPrintPreview *preview,
+			gpointer user_data)
+{
+	EomPrintImageSetupPrivate *priv = EOM_PRINT_IMAGE_SETUP (user_data)->priv;
+	gdouble x, y;
+
+	eom_print_preview_get_image_position (preview, &x, &y);
+
+	if (priv->current_unit == GTK_UNIT_MM) {
+		x *= FACTOR_INCH_TO_MM;
+		y *= FACTOR_INCH_TO_MM;
+	}
+
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->left), x);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->top), y);
+}
+
+/* Function taken from gtkprintunixdialog.c */
+static GtkWidget *
+wrap_in_frame (const gchar *label,
+               GtkWidget   *child)
+{
+	GtkWidget *frame, *label_widget;
+	gchar *bold_text;
+
+	label_widget = gtk_label_new ("");
+	gtk_widget_set_halign (label_widget, GTK_ALIGN_START);
+	gtk_widget_show (label_widget);
+
+	bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
+	gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
+	g_free (bold_text);
+
+	frame = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+	gtk_box_pack_start (GTK_BOX (frame), label_widget, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (frame), child, FALSE, FALSE, 0);
+
+	gtk_widget_set_margin_start (child, 12);
+
+	gtk_widget_show (frame);
+
+	return frame;
+}
+
+static GtkWidget *
+grid_attach_spin_button_with_label (GtkWidget *grid,
+				     const gchar* text_label,
+				     gint left, gint top)
+{
+	GtkWidget *label, *spin_button;
+
+	label = gtk_label_new_with_mnemonic (text_label);
+	gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+	spin_button = gtk_spin_button_new_with_range (0, 100, 0.01);
+	gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spin_button), 2);
+	gtk_entry_set_width_chars (GTK_ENTRY (spin_button), 6);
+	gtk_grid_attach (GTK_GRID (grid), label, left, top, 1, 1);
+	gtk_grid_attach_next_to (GTK_GRID (grid), spin_button, label,
+							 GTK_POS_RIGHT, 1, 1);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);
+
+	return spin_button;
+}
+
+static void
+eom_print_image_setup_set_property (GObject      *object,
+				    guint         prop_id,
+				    const GValue *value,
+				    GParamSpec   *pspec)
+{
+	EomPrintImageSetup *setup = EOM_PRINT_IMAGE_SETUP (object);
+	EomPrintImageSetupPrivate *priv = setup->priv;
+	GdkPixbuf *pixbuf;
+
+	switch (prop_id) {
+	case PROP_IMAGE:
+		if (priv->image) {
+			g_object_unref (priv->image);
+		}
+		priv->image = EOM_IMAGE (g_value_dup_object (value));
+		if (EOM_IS_IMAGE (priv->image)) {
+			pixbuf = eom_image_get_pixbuf (priv->image);
+			g_object_set (priv->preview, "image",
+				      pixbuf, NULL);
+			g_object_unref (pixbuf);
+		}
+		break;
+	case PROP_PAGE_SETUP:
+		priv->page_setup = g_value_get_object (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+eom_print_image_setup_get_property (GObject    *object,
+				    guint       prop_id,
+				    GValue     *value,
+				    GParamSpec *pspec)
+{
+	EomPrintImageSetup *setup = EOM_PRINT_IMAGE_SETUP (object);
+	EomPrintImageSetupPrivate *priv = setup->priv;
+
+	switch (prop_id) {
+	case PROP_IMAGE:
+		g_value_set_object (value, priv->image);
+		break;
+	case PROP_PAGE_SETUP:
+		g_value_set_object (value, priv->page_setup);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+set_initial_values (EomPrintImageSetup *setup)
+{
+	EomPrintImageSetupPrivate *priv;
+	GtkPageSetup *page_setup;
+	EomImage *image;
+	gdouble page_width, page_height;
+	gint pix_width, pix_height;
+	gdouble factor;
+	gdouble width, height;
+	gdouble max_perc;
+
+	priv = setup->priv;
+	page_setup = priv->page_setup;
+	image = priv->image;
+
+	factor = get_scale_to_px_factor (setup);
+
+	eom_image_get_size (image, &pix_width, &pix_height);
+	width = (gdouble)pix_width/factor;
+	height = (gdouble)pix_height/factor;
+
+	max_perc = get_max_percentage (setup);
+
+	width *= max_perc;
+	height *= max_perc;
+
+	gtk_range_set_range (GTK_RANGE (priv->scaling), 1, 100*max_perc);
+	gtk_range_set_increments (GTK_RANGE (priv->scaling), max_perc, 10*max_perc);
+	gtk_range_set_value (GTK_RANGE (priv->scaling), 100*max_perc);
+
+	eom_print_preview_set_scale (EOM_PRINT_PREVIEW (priv->preview), max_perc);
+	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->width), 0, width);
+	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->height), 0, height);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->width), width);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->height), height);
+
+	gtk_combo_box_set_active (GTK_COMBO_BOX (priv->center),
+				  CENTER_BOTH);
+
+	center (gtk_page_setup_get_page_width (priv->page_setup, priv->current_unit),
+		gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->width)),
+		GTK_SPIN_BUTTON (priv->left), GTK_SPIN_BUTTON (priv->right));
+	center (gtk_page_setup_get_page_height (priv->page_setup, priv->current_unit),
+		gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->height)),
+		GTK_SPIN_BUTTON (priv->top), GTK_SPIN_BUTTON (priv->bottom));
+
+	page_width = gtk_page_setup_get_page_width (page_setup, priv->current_unit);
+	page_height = gtk_page_setup_get_page_height (page_setup, priv->current_unit);
+
+	update_image_pos_ranges (setup, page_width, page_height, width, height);
+
+
+}
+
+static void
+connect_signals (EomPrintImageSetup *setup)
+{
+	EomPrintImageSetupPrivate *priv;
+
+	priv = setup->priv;
+
+	g_signal_connect (G_OBJECT (priv->left), "value-changed",
+			  G_CALLBACK (on_left_value_changed), setup);
+	g_signal_connect (G_OBJECT (priv->right), "value-changed",
+			  G_CALLBACK (on_right_value_changed), setup);
+	g_signal_connect (G_OBJECT (priv->top), "value-changed",
+			  G_CALLBACK (on_top_value_changed), setup);
+	g_signal_connect (G_OBJECT (priv->bottom), "value-changed",
+			  G_CALLBACK (on_bottom_value_changed), setup);
+	g_signal_connect (G_OBJECT (priv->width), "value-changed",
+			  G_CALLBACK (on_width_value_changed), setup);
+	g_signal_connect (G_OBJECT (priv->height), "value-changed",
+			  G_CALLBACK (on_height_value_changed), setup);
+	g_signal_connect (G_OBJECT (priv->scaling), "value-changed",
+			  G_CALLBACK (on_scale_changed), setup);
+	g_signal_connect (G_OBJECT (priv->scaling), "format-value",
+			  G_CALLBACK (on_scale_format_value), NULL);
+	g_signal_connect (G_OBJECT (priv->preview), "image-moved",
+			  G_CALLBACK (on_preview_image_moved), setup);
+}
+
+static void
+eom_print_image_setup_class_init (EomPrintImageSetupClass *class)
+{
+	GObjectClass *object_class = (GObjectClass *)class;
+
+	object_class->set_property = eom_print_image_setup_set_property;
+	object_class->get_property = eom_print_image_setup_get_property;
+
+	g_object_class_install_property (object_class, PROP_IMAGE,
+					 g_param_spec_object ("image",
+							      _("Image"),
+							      _("The image whose printing properties will be set up"),
+							      EOM_TYPE_IMAGE,
+							      G_PARAM_READWRITE));
+
+	g_object_class_install_property (object_class, PROP_PAGE_SETUP,
+					 g_param_spec_object ("page-setup",
+							      _("Page Setup"),
+							      _("The information for the page where the image will be printed"),
+							      GTK_TYPE_PAGE_SETUP,
+							      G_PARAM_READWRITE));
+}
+
+static void
+eom_print_image_setup_init (EomPrintImageSetup *setup)
+{
+	GtkWidget *frame;
+	GtkWidget *grid;
+	GtkWidget *label;
+	GtkWidget *hscale;
+	GtkWidget *combobox;
+	EomPrintImageSetupPrivate *priv;
+
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+	gchar *locale_scale = NULL;
+#endif
+
+	priv = setup->priv = eom_print_image_setup_get_instance_private (setup);
+
+	priv->image = NULL;
+
+	grid = gtk_grid_new ();
+	gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
+	gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
+	frame = wrap_in_frame (_("Position"), grid);
+	gtk_grid_attach (GTK_GRID (setup), frame, 0, 0, 1, 1);
+
+	priv->left = grid_attach_spin_button_with_label (grid,
+													 _("_Left:"), 0, 0);
+	priv->right = grid_attach_spin_button_with_label (grid,
+													  _("_Right:"), 0, 1);
+	priv->top = grid_attach_spin_button_with_label (grid, _("_Top:"), 2, 0);
+	priv->bottom = grid_attach_spin_button_with_label (grid, _("_Bottom:"),
+													   2, 1);
+
+	label = gtk_label_new_with_mnemonic (_("C_enter:"));
+	gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+
+	combobox = gtk_combo_box_text_new ();
+	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox),
+				   CENTER_NONE, _("None"));
+	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox),
+				   CENTER_HORIZONTAL, _("Horizontal"));
+	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox),
+				   CENTER_VERTICAL, _("Vertical"));
+	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox),
+				   CENTER_BOTH, _("Both"));
+	gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), CENTER_NONE);
+	/* Attach combobox below right margin spinbutton and span until end */
+	gtk_grid_attach_next_to (GTK_GRID (grid), combobox, priv->right,
+							 GTK_POS_BOTTOM, 3, 1);
+	/* Attach the label to the left of the combobox */
+	gtk_grid_attach_next_to (GTK_GRID (grid), label, combobox, GTK_POS_LEFT,
+							 1, 1);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), combobox);
+	priv->center = combobox;
+	g_signal_connect (G_OBJECT (combobox), "changed",
+			  G_CALLBACK (on_center_changed), setup);
+
+	grid = gtk_grid_new ();
+	gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
+	gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
+	frame = wrap_in_frame (_("Size"), grid);
+	gtk_grid_attach (GTK_GRID (setup), frame, 0, 1, 1, 1);
+
+	priv->width = grid_attach_spin_button_with_label (grid, _("_Width:"),
+							   0, 0);
+	priv->height = grid_attach_spin_button_with_label (grid, _("_Height:"),
+							    2, 0);
+
+	label = gtk_label_new_with_mnemonic (_("_Scaling:"));
+	hscale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 1, 100, 1);
+	gtk_scale_set_value_pos (GTK_SCALE (hscale), GTK_POS_RIGHT);
+	gtk_range_set_value (GTK_RANGE (hscale), 100);
+	gtk_grid_attach_next_to (GTK_GRID (grid), hscale, priv->width,
+							 GTK_POS_BOTTOM, 3, 1);
+	gtk_grid_attach_next_to (GTK_GRID (grid), label, hscale, GTK_POS_LEFT,
+							 1, 1);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), hscale);
+	priv->scaling = hscale;
+
+	label = gtk_label_new_with_mnemonic (_("_Unit:"));
+	gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+
+	combobox = gtk_combo_box_text_new ();
+	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox), UNIT_MM,
+				   _("Millimeters"));
+	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox), UNIT_INCH,
+				   _("Inches"));
+
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+	locale_scale = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
+	if (locale_scale && locale_scale[0] == 2) {
+		gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), UNIT_INCH);
+		set_scale_unit (setup, GTK_UNIT_INCH);
+	} else
+#endif
+	{
+		gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), UNIT_MM);
+		set_scale_unit (setup, GTK_UNIT_MM);
+	}
+
+	gtk_grid_attach_next_to (GTK_GRID (grid), combobox, hscale,
+							 GTK_POS_BOTTOM, 3, 1);
+	gtk_grid_attach_next_to (GTK_GRID (grid), label, combobox, GTK_POS_LEFT,
+							 1, 1);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), combobox);
+	priv->unit = combobox;
+	g_signal_connect (G_OBJECT (combobox), "changed",
+			  G_CALLBACK (on_unit_changed), setup);
+
+	priv->preview = eom_print_preview_new ();
+
+	/* FIXME: This shouldn't be set by hand */
+	gtk_widget_set_size_request (priv->preview, 250, 250);
+
+	frame = wrap_in_frame (_("Preview"), priv->preview);
+	/* The preview widget needs to span the whole grid height */
+	gtk_grid_attach (GTK_GRID (setup), frame, 1, 0, 1, 2);
+
+	gtk_widget_show_all (GTK_WIDGET (setup));
+}
+
+
+/**
+ * eom_print_image_setup_new:
+ * @image: the #EomImage to print
+ * @page_setup: a #GtkPageSetup specifying the page where
+ * the image will be print
+ *
+ * Creates a new #EomPrintImageSetup widget, to be used as a custom
+ * widget in a #GtkPrintUnixDialog. This widgets allows to set
+ * the image position and scale in a page.
+ *
+ * Returns: a new #EomPrintImageSetup
+ **/
+GtkWidget *
+eom_print_image_setup_new (EomImage *image, GtkPageSetup *page_setup)
+{
+	GtkWidget *setup;
+	GtkWidget *preview;
+
+	setup = g_object_new (EOM_TYPE_PRINT_IMAGE_SETUP,
+			     "orientation", GTK_ORIENTATION_VERTICAL,
+			     "row-spacing", 18,
+			     "column-spacing", 18,
+			     "border-width", 12,
+			     "image", image,
+			     "page-setup", page_setup,
+			     NULL);
+
+	set_initial_values (EOM_PRINT_IMAGE_SETUP (setup));
+
+	preview = EOM_PRINT_IMAGE_SETUP (setup)->priv->preview;
+	eom_print_preview_set_from_page_setup (EOM_PRINT_PREVIEW (preview),
+					       page_setup);
+
+	connect_signals (EOM_PRINT_IMAGE_SETUP (setup));
+
+	return setup;
+}
+
+/**
+ * eom_print_image_setup_get_options:
+ * @setup: a #EomPrintImageSetup
+ * @left: a pointer where to store the image's left position
+ * @top: a pointer where to store the image's top position
+ * @scale: a pointer where to store the image's scale
+ * @unit: a pointer where to store the #GtkUnit used by the @left and @top values.
+ *
+ * Gets the options set by the #EomPrintImageSetup.
+ **/
+void
+eom_print_image_setup_get_options (EomPrintImageSetup *setup,
+				   gdouble *left,
+				   gdouble *top,
+				   gdouble *scale,
+				   GtkUnit *unit)
+{
+	EomPrintImageSetupPrivate *priv;
+
+	g_return_if_fail (EOM_IS_PRINT_IMAGE_SETUP (setup));
+
+	priv = setup->priv;
+
+	*left = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->left));
+	*top = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->top));
+	*scale = gtk_range_get_value (GTK_RANGE (priv->scaling));
+	*unit = priv->current_unit;
+}
+
+void
+eom_print_image_setup_update (GtkPrintOperation *operation,
+			      GtkWidget         *custom_widget,
+			      GtkPageSetup      *page_setup,
+			      GtkPrintSettings  *print_settings,
+			      gpointer           user_data)
+{
+	GtkWidget *preview;
+	gdouble    pos_x;
+	gdouble    pos_y;
+	EomPrintImageSetup *setup;
+
+	setup = EOM_PRINT_IMAGE_SETUP (custom_widget);
+
+	setup->priv->page_setup = gtk_page_setup_copy (page_setup);
+
+	set_initial_values (EOM_PRINT_IMAGE_SETUP (setup));
+
+	preview = EOM_PRINT_IMAGE_SETUP (setup)->priv->preview;
+	eom_print_preview_set_from_page_setup (EOM_PRINT_PREVIEW (preview),
+					       setup->priv->page_setup);
+
+	pos_x = gtk_spin_button_get_value (GTK_SPIN_BUTTON (setup->priv->left));
+	pos_y = gtk_spin_button_get_value (GTK_SPIN_BUTTON (setup->priv->top));
+	if (setup->priv->current_unit == GTK_UNIT_MM) {
+		pos_x *= FACTOR_MM_TO_INCH;
+		pos_y *= FACTOR_MM_TO_INCH;
+	}
+	eom_print_preview_set_image_position (EOM_PRINT_PREVIEW (setup->priv->preview), pos_x, pos_y);
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/16.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/16.html new file mode 100644 index 0000000..5dfbd7e --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/16.html @@ -0,0 +1,1910 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
/* Eye Of Mate - Image Properties Dialog
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <lucasr@gnome.org>
+ *         Hubert Figuiere <hub@figuiere.net> (XMP support)
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "eom-properties-dialog.h"
+#include "eom-image.h"
+#include "eom-util.h"
+#include "eom-thumb-view.h"
+
+#if HAVE_EXIF
+#include "eom-exif-util.h"
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#if HAVE_EXEMPI
+#include <exempi/xmp.h>
+#include <exempi/xmpconsts.h>
+#endif
+#if HAVE_EXIF || HAVE_EXEMPI
+#define HAVE_METADATA 1
+#endif
+
+#if HAVE_METADATA
+#include "eom-metadata-details.h"
+#endif
+
+enum {
+        PROP_0,
+        PROP_THUMBVIEW,
+        PROP_NETBOOK_MODE
+};
+
+struct _EomPropertiesDialogPrivate {
+	EomThumbView   *thumbview;
+
+	gboolean        update_page;
+	EomPropertiesDialogPage current_page;
+
+	GtkWidget      *notebook;
+	GtkWidget      *close_button;
+	GtkWidget      *next_button;
+	GtkWidget      *previous_button;
+
+	GtkWidget      *general_box;
+	GtkWidget      *thumbnail_image;
+	GtkWidget      *name_label;
+	GtkWidget      *width_label;
+	GtkWidget      *height_label;
+	GtkWidget      *type_label;
+	GtkWidget      *bytes_label;
+	GtkWidget      *folder_button;
+	gchar          *folder_button_uri;
+#ifdef HAVE_EXIF
+	GtkWidget      *exif_aperture_label;
+	GtkWidget      *exif_exposure_label;
+	GtkWidget      *exif_focal_label;
+	GtkWidget      *exif_flash_label;
+	GtkWidget      *exif_iso_label;
+	GtkWidget      *exif_metering_label;
+	GtkWidget      *exif_model_label;
+	GtkWidget      *exif_date_label;
+#endif
+#ifdef HAVE_EXEMPI
+	GtkWidget      *xmp_location_label;
+	GtkWidget      *xmp_description_label;
+	GtkWidget      *xmp_keywords_label;
+	GtkWidget      *xmp_creator_label;
+	GtkWidget      *xmp_rights_label;
+#else
+	GtkWidget      *xmp_box;
+	GtkWidget      *xmp_box_label;
+#endif
+#if HAVE_METADATA
+	GtkWidget      *metadata_box;
+	GtkWidget      *metadata_details_expander;
+	GtkWidget      *metadata_details;
+	GtkWidget      *metadata_details_box;
+	GtkWidget      *metadata_details_sw;
+#endif
+
+	gboolean        netbook_mode;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomPropertiesDialog, eom_properties_dialog, GTK_TYPE_DIALOG);
+
+static void
+parent_file_display_name_query_info_cb (GObject *source_object,
+					GAsyncResult *res,
+					gpointer user_data)
+{
+	EomPropertiesDialog *prop_dlg = EOM_PROPERTIES_DIALOG (user_data);
+	GFile *parent_file = G_FILE (source_object);
+	GFileInfo *file_info;
+	gchar *display_name;
+
+
+	file_info = g_file_query_info_finish (parent_file, res, NULL);
+	if (file_info == NULL) {
+		display_name = g_file_get_basename (parent_file);
+	} else {
+		display_name = g_strdup (
+			g_file_info_get_display_name (file_info));
+		g_object_unref (file_info);
+	}
+	gtk_button_set_label (GTK_BUTTON (prop_dlg->priv->folder_button),
+			      display_name);
+	gtk_widget_set_sensitive (prop_dlg->priv->folder_button, TRUE);
+
+	g_free (display_name);
+	g_object_unref (prop_dlg);
+}
+
+static void
+pd_update_general_tab (EomPropertiesDialog *prop_dlg,
+		       EomImage            *image)
+{
+	gchar *bytes_str, *dir_str_long;
+	gchar *width_str, *height_str;
+	GFile *file, *parent_file;
+	GFileInfo *file_info;
+	const char *mime_str;
+	char *type_str;
+	gint width, height;
+	goffset bytes;
+
+	g_object_set (G_OBJECT (prop_dlg->priv->thumbnail_image),
+		      "pixbuf", eom_image_get_thumbnail (image),
+		      NULL);
+
+	gtk_label_set_text (GTK_LABEL (prop_dlg->priv->name_label),
+			    eom_image_get_caption (image));
+
+	eom_image_get_size (image, &width, &height);
+
+	width_str = g_strdup_printf ("%d %s", width,
+				     ngettext ("pixel", "pixels", width));
+	height_str = g_strdup_printf ("%d %s", height,
+				      ngettext ("pixel", "pixels", height));
+
+	gtk_label_set_text (GTK_LABEL (prop_dlg->priv->width_label), width_str);
+
+	gtk_label_set_text (GTK_LABEL (prop_dlg->priv->height_label),
+			    height_str);
+
+	g_free (height_str);
+	g_free (width_str);
+
+	file = eom_image_get_file (image);
+	file_info = g_file_query_info (file,
+				       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+				       0, NULL, NULL);
+	if (file_info == NULL) {
+		type_str = g_strdup (_("Unknown"));
+	} else {
+		mime_str = g_file_info_get_content_type (file_info);
+		type_str = g_content_type_get_description (mime_str);
+		g_object_unref (file_info);
+	}
+
+	gtk_label_set_text (GTK_LABEL (prop_dlg->priv->type_label), type_str);
+
+	bytes = eom_image_get_bytes (image);
+	bytes_str = g_format_size (bytes);
+
+	gtk_label_set_text (GTK_LABEL (prop_dlg->priv->bytes_label), bytes_str);
+
+	parent_file = g_file_get_parent (file);
+	if (parent_file == NULL) {
+		/* file is root directory itself */
+		parent_file = g_object_ref (file);
+	}
+
+	gtk_widget_set_sensitive (prop_dlg->priv->folder_button, FALSE);
+	gtk_button_set_label (GTK_BUTTON (prop_dlg->priv->folder_button), NULL);
+
+	dir_str_long = g_file_get_path (parent_file);
+	gtk_widget_set_tooltip_text (GTK_WIDGET (prop_dlg->priv->folder_button),
+	                             dir_str_long);
+
+	g_free (prop_dlg->priv->folder_button_uri);
+	prop_dlg->priv->folder_button_uri = g_file_get_uri (parent_file);
+
+	g_file_query_info_async (parent_file,
+				 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+				 G_FILE_QUERY_INFO_NONE,
+				 G_PRIORITY_DEFAULT,
+				 NULL,
+				 parent_file_display_name_query_info_cb,
+				 g_object_ref (prop_dlg));
+
+	g_object_unref (parent_file);
+
+	g_free (type_str);
+	g_free (bytes_str);
+	g_free (dir_str_long);
+}
+
+#if HAVE_EXEMPI
+static void
+eom_xmp_set_label (XmpPtr xmp,
+		   const char *ns,
+		   const char *propname,
+		   GtkWidget *w)
+{
+	uint32_t options;
+
+	XmpStringPtr value = xmp_string_new ();
+
+	if (xmp_get_property (xmp, ns, propname, value, &options)) {
+		if (XMP_IS_PROP_SIMPLE (options)) {
+			gtk_label_set_text (GTK_LABEL (w), xmp_string_cstr (value));
+		} else if (XMP_IS_PROP_ARRAY (options)) {
+			XmpIteratorPtr iter = xmp_iterator_new (xmp,
+							        ns,
+								propname,
+								XMP_ITER_JUSTLEAFNODES);
+
+			GString *string = g_string_new ("");
+
+			if (iter) {
+				gboolean first = TRUE;
+
+				while (xmp_iterator_next (iter, NULL, NULL, value, &options)
+				       && !XMP_IS_PROP_QUALIFIER (options)) {
+
+					if (!first) {
+						g_string_append_printf(string, ", ");
+					} else {
+						first = FALSE;
+					}
+
+					g_string_append_printf (string,
+								"%s",
+								xmp_string_cstr (value));
+				}
+
+				xmp_iterator_free (iter);
+			}
+
+			gtk_label_set_text (GTK_LABEL (w), string->str);
+			g_string_free (string, TRUE);
+		}
+	} else {
+		/* Property was not found */
+		/* Clear label so it won't show bogus data */
+		gtk_label_set_text (GTK_LABEL (w), NULL);
+	}
+
+	xmp_string_free (value);
+}
+#endif
+
+#if HAVE_METADATA
+static void
+pd_update_metadata_tab (EomPropertiesDialog *prop_dlg,
+			EomImage            *image)
+{
+	EomPropertiesDialogPrivate *priv;
+	GtkNotebook *notebook;
+#if HAVE_EXIF
+	ExifData    *exif_data;
+#endif
+#if HAVE_EXEMPI
+	XmpPtr      xmp_data;
+#endif
+
+	g_return_if_fail (EOM_IS_PROPERTIES_DIALOG (prop_dlg));
+
+	priv = prop_dlg->priv;
+
+	notebook = GTK_NOTEBOOK (priv->notebook);
+
+	if (TRUE
+#if HAVE_EXIF
+	    && !eom_image_has_data (image, EOM_IMAGE_DATA_EXIF)
+#endif
+#if HAVE_EXEMPI
+	    && !eom_image_has_data (image, EOM_IMAGE_DATA_XMP)
+#endif
+	    ) {
+		if (gtk_notebook_get_current_page (notebook) ==	EOM_PROPERTIES_DIALOG_PAGE_EXIF) {
+			gtk_notebook_prev_page (notebook);
+		} else if (gtk_notebook_get_current_page (notebook) == EOM_PROPERTIES_DIALOG_PAGE_DETAILS) {
+			gtk_notebook_set_current_page (notebook, EOM_PROPERTIES_DIALOG_PAGE_GENERAL);
+		}
+
+		if (gtk_widget_get_visible (priv->metadata_box)) {
+			gtk_widget_hide (priv->metadata_box);
+		}
+		if (gtk_widget_get_visible (priv->metadata_details_box)) {
+			gtk_widget_hide (priv->metadata_details_box);
+		}
+
+		return;
+	} else {
+		if (!gtk_widget_get_visible (priv->metadata_box))
+			gtk_widget_show_all (priv->metadata_box);
+		if (priv->netbook_mode &&
+		    !gtk_widget_get_visible (priv->metadata_details_box)) {
+			gtk_widget_show_all (priv->metadata_details_box);
+			gtk_widget_hide (priv->metadata_details_expander);
+		}
+	}
+
+#if HAVE_EXIF
+	exif_data = (ExifData *) eom_image_get_exif_info (image);
+
+	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_aperture_label),
+				      exif_data, EXIF_TAG_FNUMBER);
+
+	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_exposure_label),
+				      exif_data, EXIF_TAG_EXPOSURE_TIME);
+
+	eom_exif_util_set_focal_length_label_text (GTK_LABEL (priv->exif_focal_label), exif_data);
+
+	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_flash_label),
+				      exif_data, EXIF_TAG_FLASH);
+
+	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_iso_label),
+				      exif_data, EXIF_TAG_ISO_SPEED_RATINGS);
+
+
+	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_metering_label),
+				      exif_data, EXIF_TAG_METERING_MODE);
+
+	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_model_label),
+				      exif_data, EXIF_TAG_MODEL);
+
+	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_date_label),
+				      exif_data, EXIF_TAG_DATE_TIME_ORIGINAL);
+
+	eom_metadata_details_update (EOM_METADATA_DETAILS (priv->metadata_details),
+				 exif_data);
+
+	/* exif_data_unref can handle NULL-values */
+	exif_data_unref(exif_data);
+#endif
+
+#if HAVE_EXEMPI
+	xmp_data = (XmpPtr) eom_image_get_xmp_info (image);
+
+ 	if (xmp_data != NULL) {
+		eom_xmp_set_label (xmp_data,
+				   NS_IPTC4XMP,
+				   "Location",
+				   priv->xmp_location_label);
+
+		eom_xmp_set_label (xmp_data,
+				   NS_DC,
+				   "description",
+				   priv->xmp_description_label);
+
+		eom_xmp_set_label (xmp_data,
+				   NS_DC,
+				   "subject",
+				   priv->xmp_keywords_label);
+
+		eom_xmp_set_label (xmp_data,
+				   NS_DC,
+        	                   "creator",
+				   priv->xmp_creator_label);
+
+		eom_xmp_set_label (xmp_data,
+				   NS_DC,
+				   "rights",
+				   priv->xmp_rights_label);
+
+		eom_metadata_details_xmp_update (EOM_METADATA_DETAILS (priv->metadata_details), xmp_data);
+
+		xmp_free (xmp_data);
+	} else {
+		/* Image has no XMP data */
+
+		/* Clear the labels so they won't display foreign data.*/
+
+		gtk_label_set_text (GTK_LABEL (priv->xmp_location_label), NULL);
+		gtk_label_set_text (GTK_LABEL (priv->xmp_description_label),
+				    NULL);
+		gtk_label_set_text (GTK_LABEL (priv->xmp_keywords_label), NULL);
+		gtk_label_set_text (GTK_LABEL (priv->xmp_creator_label), NULL);
+		gtk_label_set_text (GTK_LABEL (priv->xmp_rights_label), NULL);
+	}
+#endif
+}
+
+static gboolean
+pd_resize_dialog (gpointer user_data)
+{
+	gint width, height;
+
+	gtk_window_get_size (GTK_WINDOW (user_data),
+			     &width,
+			     &height);
+
+	gtk_window_resize (GTK_WINDOW (user_data), width, 1);
+
+	return FALSE;
+}
+
+static void
+pd_exif_details_activated_cb (GtkExpander *expander,
+			      GParamSpec *param_spec,
+			      GtkWidget *dialog)
+{
+	gboolean expanded;
+
+	expanded = gtk_expander_get_expanded (expander);
+
+	/*FIXME: this is depending on the expander animation
+         * duration. Need to find a safer way for doing that. */
+	if (!expanded)
+		g_timeout_add (150, pd_resize_dialog, dialog);
+}
+#endif
+
+static void
+pd_folder_button_clicked_cb (GtkButton *button, gpointer data)
+{
+	EomPropertiesDialogPrivate *priv = EOM_PROPERTIES_DIALOG (data)->priv;
+	GtkWindow *window;
+	guint32 timestamp;
+
+	if (!priv->folder_button_uri)
+		return;
+
+	timestamp = gtk_get_current_event_time ();
+
+	window = GTK_WINDOW (data);
+	gtk_show_uri_on_window (window, priv->folder_button_uri, timestamp, NULL);
+}
+
+static gboolean
+eom_properties_dialog_page_switch (GtkNotebook     *notebook,
+				   gpointer         page,
+				   guint            page_index,
+				   EomPropertiesDialog *prop_dlg)
+{
+	if (prop_dlg->priv->update_page)
+		prop_dlg->priv->current_page = page_index;
+
+	return TRUE;
+}
+
+void
+eom_properties_dialog_set_netbook_mode (EomPropertiesDialog *dlg,
+					gboolean enable)
+{
+	EomPropertiesDialogPrivate *priv;
+
+	g_return_if_fail (EOM_IS_PROPERTIES_DIALOG (dlg));
+
+	priv = dlg->priv;
+
+	if (priv->netbook_mode == enable)
+		return;
+
+	priv->netbook_mode = enable;
+
+#ifdef HAVE_METADATA
+	if (enable) {
+		g_object_ref (priv->metadata_details_sw);
+		gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (priv->metadata_details_sw)),
+				      priv->metadata_details_sw);
+		gtk_container_add (GTK_CONTAINER (priv->metadata_details_box), priv->metadata_details_sw);
+		g_object_unref (priv->metadata_details_sw);
+		// Only show details box if metadata is being displayed
+		if (gtk_widget_get_visible (priv->metadata_box))
+			gtk_widget_show_all (priv->metadata_details_box);
+
+		gtk_widget_hide (priv->metadata_details_expander);
+	} else {
+		g_object_ref (priv->metadata_details_sw);
+		gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (priv->metadata_details_sw)),
+				      priv->metadata_details_sw);
+		gtk_container_add (GTK_CONTAINER (priv->metadata_details_expander), priv->metadata_details_sw);
+		g_object_unref (priv->metadata_details_sw);
+		gtk_widget_show_all (priv->metadata_details_expander);
+
+		if (gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)) == EOM_PROPERTIES_DIALOG_PAGE_DETAILS)
+			gtk_notebook_prev_page (GTK_NOTEBOOK (priv->notebook));
+		gtk_widget_hide (priv->metadata_details_box);
+	}
+#endif
+}
+
+static void
+eom_properties_dialog_set_property (GObject      *object,
+				    guint         prop_id,
+				    const GValue *value,
+				    GParamSpec   *pspec)
+{
+	EomPropertiesDialog *prop_dlg = EOM_PROPERTIES_DIALOG (object);
+
+	switch (prop_id) {
+		case PROP_THUMBVIEW:
+			prop_dlg->priv->thumbview = g_value_get_object (value);
+			break;
+		case PROP_NETBOOK_MODE:
+			eom_properties_dialog_set_netbook_mode (prop_dlg,
+						   g_value_get_boolean (value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+							   pspec);
+			break;
+	}
+}
+
+static void
+eom_properties_dialog_get_property (GObject    *object,
+				    guint       prop_id,
+				    GValue     *value,
+				    GParamSpec *pspec)
+{
+	EomPropertiesDialog *prop_dlg = EOM_PROPERTIES_DIALOG (object);
+
+	switch (prop_id) {
+		case PROP_THUMBVIEW:
+			g_value_set_object (value, prop_dlg->priv->thumbview);
+			break;
+		case PROP_NETBOOK_MODE:
+			g_value_set_boolean (value,
+					     prop_dlg->priv->netbook_mode);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
+							   pspec);
+			break;
+	}
+}
+
+static void
+eom_properties_dialog_dispose (GObject *object)
+{
+	EomPropertiesDialog *prop_dlg;
+	EomPropertiesDialogPrivate *priv;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (EOM_IS_PROPERTIES_DIALOG (object));
+
+	prop_dlg = EOM_PROPERTIES_DIALOG (object);
+	priv = prop_dlg->priv;
+
+	if (priv->thumbview) {
+		g_object_unref (priv->thumbview);
+		priv->thumbview = NULL;
+	}
+
+	g_free (priv->folder_button_uri);
+	priv->folder_button_uri = NULL;
+
+	G_OBJECT_CLASS (eom_properties_dialog_parent_class)->dispose (object);
+}
+
+static void
+eom_properties_dialog_class_init (EomPropertiesDialogClass *klass)
+{
+	GObjectClass *g_object_class = (GObjectClass *) klass;
+
+	g_object_class->dispose = eom_properties_dialog_dispose;
+	g_object_class->set_property = eom_properties_dialog_set_property;
+	g_object_class->get_property = eom_properties_dialog_get_property;
+
+	g_object_class_install_property (g_object_class,
+					 PROP_THUMBVIEW,
+					 g_param_spec_object ("thumbview",
+							      "Thumbview",
+							      "Thumbview",
+							      EOM_TYPE_THUMB_VIEW,
+							      G_PARAM_READWRITE |
+							      G_PARAM_CONSTRUCT_ONLY |
+							      G_PARAM_STATIC_NAME |
+							      G_PARAM_STATIC_NICK |
+							      G_PARAM_STATIC_BLURB));
+	g_object_class_install_property (g_object_class, PROP_NETBOOK_MODE,
+					 g_param_spec_boolean ("netbook-mode",
+					 		      "Netbook Mode",
+							      "Netbook Mode",
+							      FALSE,
+							      G_PARAM_READWRITE |
+							      G_PARAM_STATIC_STRINGS));
+
+	GtkWidgetClass *wklass = (GtkWidgetClass*) klass;
+
+	gtk_widget_class_set_template_from_resource (wklass,
+	                                             "/org/mate/eom/ui/eom-image-properties-dialog.ui");
+
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     notebook);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     previous_button);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     next_button);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     close_button);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     thumbnail_image);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     general_box);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     name_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     width_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     height_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     type_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     bytes_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     folder_button);
+
+#if HAVE_EXIF
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     exif_aperture_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     exif_exposure_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     exif_focal_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     exif_flash_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     exif_iso_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     exif_metering_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     exif_model_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     exif_date_label);
+#endif
+#if HAVE_EXEMPI
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     xmp_location_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     xmp_description_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     xmp_keywords_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     xmp_creator_label);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     xmp_rights_label);
+#else
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     xmp_box);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     xmp_box_label);
+#endif
+#ifdef HAVE_METADATA
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     metadata_box);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     metadata_details_expander);
+	gtk_widget_class_bind_template_child_private(wklass,
+						     EomPropertiesDialog,
+						     metadata_details_box);
+
+	gtk_widget_class_bind_template_callback(wklass,
+						pd_exif_details_activated_cb);
+#endif
+	gtk_widget_class_bind_template_callback(wklass,
+						eom_properties_dialog_page_switch);
+	gtk_widget_class_bind_template_callback(wklass,
+						pd_folder_button_clicked_cb);
+}
+
+static void
+eom_properties_dialog_init (EomPropertiesDialog *prop_dlg)
+{
+	EomPropertiesDialogPrivate *priv;
+#if HAVE_METADATA
+	GtkWidget *sw;
+#endif
+
+	prop_dlg->priv = eom_properties_dialog_get_instance_private (prop_dlg);
+
+	priv = prop_dlg->priv;
+
+	priv->update_page = FALSE;
+
+	gtk_widget_init_template (GTK_WIDGET (prop_dlg));
+
+	g_signal_connect (prop_dlg,
+	                  "delete-event",
+	                 G_CALLBACK (gtk_widget_hide_on_delete),
+	                 prop_dlg);
+
+	g_signal_connect_swapped (priv->close_button,
+	                          "clicked",
+	                          G_CALLBACK (gtk_widget_hide_on_delete),
+	                          prop_dlg);
+
+	gtk_widget_set_size_request (priv->thumbnail_image, 100, 100);
+
+#ifdef HAVE_METADATA
+ 	sw = gtk_scrolled_window_new (NULL, NULL);
+
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
+					     GTK_SHADOW_IN);
+
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
+
+	priv->metadata_details = eom_metadata_details_new ();
+	gtk_widget_set_size_request (priv->metadata_details, -1, 170);
+	gtk_container_set_border_width (GTK_CONTAINER (sw), 6);
+	gtk_widget_set_vexpand (priv->metadata_details, TRUE);
+
+	gtk_container_add (GTK_CONTAINER (sw), priv->metadata_details);
+	gtk_widget_show_all (sw);
+
+	priv->metadata_details_sw = sw;
+
+	if (priv->netbook_mode) {
+		gtk_widget_hide (priv->metadata_details_expander);
+		gtk_box_pack_start (GTK_BOX (priv->metadata_details_box),
+				    sw, TRUE, TRUE, 6);
+	} else {
+		gtk_container_add (GTK_CONTAINER (priv->metadata_details_expander),
+				   sw);
+	}
+
+#ifndef HAVE_EXEMPI
+	gtk_widget_hide (priv->xmp_box);
+	gtk_widget_hide (priv->xmp_box_label);
+#endif
+
+#else
+	/* Remove pages from back to front. Otherwise the page index
+	 * needs to be adjusted when deleting the next page. */
+	gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook),
+				  EOM_PROPERTIES_DIALOG_PAGE_DETAILS);
+	gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook),
+				  EOM_PROPERTIES_DIALOG_PAGE_EXIF);
+#endif
+
+    /* Add tab scrolling support for GTK3 */
+    gtk_widget_add_events (priv->notebook, GDK_SCROLL_MASK);
+    g_signal_connect (priv->notebook,
+                      "scroll-event",
+                      G_CALLBACK (eom_notebook_page_scroll_event_cb),
+                      NULL);
+}
+
+/**
+ * eom_properties_dialog_new:
+ * @parent: the dialog's parent window
+ * @thumbview:
+ * @next_image_action:
+ * @previous_image_action:
+ *
+ *
+ *
+ * Returns: (transfer full) (type EomPropertiesDialog): a new #EomPropertiesDialog
+ **/
+
+GtkWidget *
+eom_properties_dialog_new (GtkWindow    *parent,
+			   EomThumbView *thumbview,
+			   GtkAction    *next_image_action,
+			   GtkAction    *previous_image_action)
+{
+	GObject *prop_dlg;
+
+	g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
+	g_return_val_if_fail (EOM_IS_THUMB_VIEW (thumbview), NULL);
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	g_return_val_if_fail (GTK_IS_ACTION (next_image_action), NULL);
+	g_return_val_if_fail (GTK_IS_ACTION (previous_image_action), NULL);
+
+	prop_dlg = g_object_new (EOM_TYPE_PROPERTIES_DIALOG,
+	                         "thumbview", thumbview,
+	                         NULL);
+
+	if (parent) {
+		gtk_window_set_transient_for (GTK_WINDOW (prop_dlg), parent);
+	}
+
+	gtk_activatable_set_related_action (GTK_ACTIVATABLE (EOM_PROPERTIES_DIALOG (prop_dlg)->priv->next_button), next_image_action);
+
+	gtk_activatable_set_related_action (GTK_ACTIVATABLE (EOM_PROPERTIES_DIALOG (prop_dlg)->priv->previous_button), previous_image_action);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	return GTK_WIDGET (prop_dlg);
+}
+
+void
+eom_properties_dialog_update (EomPropertiesDialog *prop_dlg,
+			      EomImage            *image)
+{
+	g_return_if_fail (EOM_IS_PROPERTIES_DIALOG (prop_dlg));
+
+	prop_dlg->priv->update_page = FALSE;
+
+	pd_update_general_tab (prop_dlg, image);
+
+#ifdef HAVE_METADATA
+	pd_update_metadata_tab (prop_dlg, image);
+#endif
+	gtk_notebook_set_current_page (GTK_NOTEBOOK (prop_dlg->priv->notebook),
+				       prop_dlg->priv->current_page);
+
+	prop_dlg->priv->update_page = TRUE;
+}
+
+void
+eom_properties_dialog_set_page (EomPropertiesDialog *prop_dlg,
+			        EomPropertiesDialogPage page)
+{
+	g_return_if_fail (EOM_IS_PROPERTIES_DIALOG (prop_dlg));
+
+	prop_dlg->priv->current_page = page;
+
+	gtk_notebook_set_current_page (GTK_NOTEBOOK (prop_dlg->priv->notebook),
+				       page);
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/17.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/17.html new file mode 100644 index 0000000..3051d30 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/17.html @@ -0,0 +1,2806 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
#include <gio/gio.h>
+
+#if defined (__ELF__) && ( __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6))
+# define SECTION __attribute__ ((section (".gresource.eom"), aligned (8)))
+#else
+# define SECTION
+#endif
+
+#ifdef _MSC_VER
+static const SECTION union { const guint8 data[9264]; const double alignment; void * const ptr;}  _eom_resource_data = { {<--- union member 'Anonymous0::alignment' is never used.<--- union member 'Anonymous0::ptr' is never used.
+  0107, 0126, 0141, 0162, 0151, 0141, 0156, 0164, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 
+  0030, 0000, 0000, 0000, 0250, 0001, 0000, 0000, 0000, 0000, 0000, 0050, 0016, 0000, 0000, 0000, 
+  0000, 0000, 0000, 0000, 0001, 0000, 0000, 0000, 0002, 0000, 0000, 0000, 0005, 0000, 0000, 0000, 
+  0005, 0000, 0000, 0000, 0006, 0000, 0000, 0000, 0006, 0000, 0000, 0000, 0007, 0000, 0000, 0000, 
+  0011, 0000, 0000, 0000, 0012, 0000, 0000, 0000, 0013, 0000, 0000, 0000, 0013, 0000, 0000, 0000, 
+  0015, 0000, 0000, 0000, 0016, 0000, 0000, 0000, 0136, 0073, 0312, 0116, 0011, 0000, 0000, 0000, 
+  0250, 0001, 0000, 0000, 0036, 0000, 0166, 0000, 0310, 0001, 0000, 0000, 0250, 0007, 0000, 0000, 
+  0113, 0120, 0220, 0013, 0003, 0000, 0000, 0000, 0250, 0007, 0000, 0000, 0004, 0000, 0114, 0000, 
+  0254, 0007, 0000, 0000, 0260, 0007, 0000, 0000, 0376, 0257, 0370, 0026, 0010, 0000, 0000, 0000, 
+  0260, 0007, 0000, 0000, 0023, 0000, 0166, 0000, 0310, 0007, 0000, 0000, 0262, 0011, 0000, 0000, 
+  0324, 0265, 0002, 0000, 0377, 0377, 0377, 0377, 0262, 0011, 0000, 0000, 0001, 0000, 0114, 0000, 
+  0264, 0011, 0000, 0000, 0270, 0011, 0000, 0000, 0022, 0363, 0015, 0161, 0011, 0000, 0000, 0000, 
+  0270, 0011, 0000, 0000, 0036, 0000, 0166, 0000, 0330, 0011, 0000, 0000, 0020, 0021, 0000, 0000, 
+  0010, 0052, 0352, 0022, 0011, 0000, 0000, 0000, 0020, 0021, 0000, 0000, 0011, 0000, 0166, 0000, 
+  0040, 0021, 0000, 0000, 0244, 0025, 0000, 0000, 0166, 0171, 0123, 0260, 0011, 0000, 0000, 0000, 
+  0244, 0025, 0000, 0000, 0007, 0000, 0166, 0000, 0260, 0025, 0000, 0000, 0150, 0026, 0000, 0000, 
+  0261, 0362, 0170, 0170, 0013, 0000, 0000, 0000, 0150, 0026, 0000, 0000, 0004, 0000, 0114, 0000, 
+  0154, 0026, 0000, 0000, 0160, 0026, 0000, 0000, 0257, 0002, 0325, 0061, 0011, 0000, 0000, 0000, 
+  0160, 0026, 0000, 0000, 0010, 0000, 0114, 0000, 0170, 0026, 0000, 0000, 0174, 0026, 0000, 0000, 
+  0176, 0300, 0216, 0312, 0007, 0000, 0000, 0000, 0174, 0026, 0000, 0000, 0003, 0000, 0114, 0000, 
+  0200, 0026, 0000, 0000, 0240, 0026, 0000, 0000, 0007, 0064, 0342, 0034, 0011, 0000, 0000, 0000, 
+  0240, 0026, 0000, 0000, 0031, 0000, 0166, 0000, 0300, 0026, 0000, 0000, 0103, 0035, 0000, 0000, 
+  0201, 0321, 0040, 0031, 0001, 0000, 0000, 0000, 0103, 0035, 0000, 0000, 0005, 0000, 0114, 0000, 
+  0110, 0035, 0000, 0000, 0114, 0035, 0000, 0000, 0011, 0156, 0067, 0122, 0011, 0000, 0000, 0000, 
+  0114, 0035, 0000, 0000, 0012, 0000, 0166, 0000, 0130, 0035, 0000, 0000, 0125, 0040, 0000, 0000, 
+  0122, 0161, 0064, 0344, 0011, 0000, 0000, 0000, 0125, 0040, 0000, 0000, 0023, 0000, 0166, 0000, 
+  0150, 0040, 0000, 0000, 0057, 0044, 0000, 0000, 0145, 0157, 0155, 0055, 0155, 0165, 0154, 0164, 
+  0151, 0160, 0154, 0145, 0055, 0163, 0141, 0166, 0145, 0055, 0141, 0163, 0055, 0144, 0151, 0141, 
+  0154, 0157, 0147, 0056, 0165, 0151, 0000, 0000, 0220, 0062, 0000, 0000, 0001, 0000, 0000, 0000, 
+  0170, 0332, 0355, 0133, 0131, 0157, 0333, 0070, 0020, 0176, 0337, 0137, 0301, 0025, 0320, 0076, 
+  0164, 0241, 0370, 0112, 0272, 0105, 0033, 0253, 0110, 0333, 0044, 0133, 0364, 0110, 0020, 0273, 
+  0317, 0002, 0055, 0215, 0055, 0066, 0024, 0251, 0245, 0050, 0073, 0006, 0366, 0307, 0357, 0120, 
+  0362, 0055, 0133, 0226, 0123, 0333, 0211, 0223, 0372, 0045, 0042, 0065, 0044, 0347, 0342, 0307, 
+  0231, 0241, 0162, 0372, 0376, 0056, 0344, 0244, 0017, 0052, 0146, 0122, 0064, 0255, 0332, 0121, 
+  0325, 0042, 0040, 0074, 0351, 0063, 0321, 0153, 0132, 0077, 0332, 0027, 0366, 0033, 0353, 0275, 
+  0363, 0307, 0351, 0237, 0266, 0115, 0056, 0101, 0200, 0242, 0032, 0174, 0062, 0140, 0072, 0040, 
+  0075, 0116, 0175, 0040, 0215, 0243, 0172, 0365, 0250, 0112, 0154, 0073, 0043, 0172, 0145, 0223, 
+  0120, 0372, 0360, 0226, 0230, 0151, 0261, 0145, 0272, 0231, 0320, 0240, 0272, 0324, 0003, 0347, 
+  0124, 0301, 0277, 0011, 0123, 0020, 0023, 0316, 0072, 0115, 0253, 0247, 0157, 0377, 0262, 0246, 
+  0213, 0067, 0216, 0152, 0307, 0126, 0305, 0071, 0225, 0235, 0237, 0340, 0151, 0342, 0161, 0032, 
+  0307, 0115, 0353, 0122, 0337, 0236, 0371, 0077, 0223, 0130, 0207, 0040, 0264, 0105, 0230, 0337, 
+  0264, 0350, 0244, 0135, 0263, 0234, 0323, 0110, 0311, 0010, 0224, 0036, 0022, 0101, 0103, 0150, 
+  0132, 0111, 0204, 0055, 0313, 0251, 0125, 0263, 0337, 0151, 0145, 0374, 0076, 0107, 0331, 0247, 
+  0074, 0001, 0244, 0054, 0040, 0211, 0065, 0104, 0056, 0023, 0236, 0202, 0164, 0365, 0102, 0332, 
+  0210, 0366, 0140, 0216, 0166, 0156, 0355, 0112, 0046, 0325, 0022, 0351, 0076, 0061, 0312, 0145, 
+  0057, 0223, 0014, 0144, 0350, 0206, 0011, 0327, 0054, 0342, 0340, 0306, 0264, 0017, 0056, 0215, 
+  0135, 0077, 0043, 0310, 0055, 0350, 0121, 0341, 0166, 0245, 0227, 0304, 0226, 0163, 0101, 0171, 
+  0014, 0005, 0274, 0101, 0037, 0131, 0102, 0272, 0313, 0117, 0137, 0334, 0353, 0253, 0317, 0337, 
+  0333, 0347, 0067, 0356, 0267, 0253, 0366, 0347, 0253, 0357, 0356, 0267, 0263, 0326, 0027, 0362, 
+  0037, 0131, 0362, 0346, 0037, 0154, 0315, 0276, 0376, 0360, 0243, 0335, 0306, 0356, 0353, 0233, 
+  0363, 0126, 0153, 0111, 0377, 0315, 0371, 0327, 0363, 0263, 0326, 0171, 0372, 0246, 0200, 0225, 
+  0216, 0124, 0076, 0050, 0167, 0300, 0174, 0035, 0130, 0316, 0111, 0001, 0245, 0146, 0232, 0203, 
+  0105, 0264, 0242, 0042, 0346, 0124, 0323, 0016, 0307, 0316, 0041, 0240, 0030, 0055, 0324, 0014, 
+  0071, 0213, 0013, 0306, 0016, 0230, 0360, 0345, 0300, 0215, 0144, 0314, 0064, 0072, 0227, 0345, 
+  0170, 0140, 0274, 0320, 0226, 0302, 0216, 0250, 0302, 0347, 0242, 0165, 0207, 0021, 0270, 0001, 
+  0063, 0066, 0314, 0124, 0077, 0113, 0353, 0005, 0214, 0373, 0044, 0165, 0151, 0101, 0271, 0235, 
+  0066, 0321, 0225, 0072, 0362, 0316, 0132, 0142, 0333, 0017, 0330, 0235, 0032, 0066, 0233, 0310, 
+  0066, 0164, 0307, 0171, 0113, 0366, 0131, 0314, 0120, 0072, 0313, 0151, 0253, 0244, 0310, 0214, 
+  0033, 0130, 0134, 0052, 0206, 0122, 0322, 0114, 0170, 0334, 0142, 0232, 0171, 0224, 0027, 0171, 
+  0172, 0104, 0075, 0334, 0363, 0226, 0123, 0137, 0057, 0055, 0365, 0314, 0264, 0056, 0352, 0221, 
+  0056, 0025, 0072, 0321, 0132, 0212, 0105, 0321, 0147, 0006, 0355, 0107, 0003, 0234, 0016, 0145, 
+  0242, 0335, 0130, 0017, 0315, 0274, 0040, 0374, 0234, 0140, 0053, 0171, 0317, 0030, 0307, 0265, 
+  0074, 0340, 0156, 0047, 0353, 0132, 0062, 0177, 0007, 0270, 0345, 0040, 0210, 0331, 0031, 0145, 
+  0021, 0324, 0154, 0056, 0336, 0032, 0112, 0005, 0036, 0260, 0076, 0040, 0072, 0100, 0227, 0042, 
+  0142, 0254, 0327, 0107, 0022, 0043, 0244, 0150, 0351, 0335, 0346, 0347, 0236, 0200, 0023, 0072, 
+  0301, 0055, 0172, 0101, 0036, 0077, 0356, 0042, 0052, 0374, 0265, 0114, 0165, 0031, 0347, 0153, 
+  0211, 0246, 0173, 0162, 0036, 0040, 0047, 0153, 0127, 0106, 0306, 0051, 0143, 0243, 0061, 0106, 
+  0226, 0060, 0222, 0041, 0265, 0151, 0374, 0333, 0112, 0033, 0132, 0251, 0126, 0154, 0245, 0322, 
+  0134, 0255, 0223, 0274, 0034, 0133, 0270, 0210, 0153, 0000, 0072, 0267, 0243, 0267, 0356, 0145, 
+  0143, 0374, 0062, 0230, 0135, 0173, 0334, 0230, 0375, 0272, 0014, 0264, 0135, 0050, 0034, 0224, 
+  0211, 0324, 0065, 0217, 0365, 0075, 0241, 0060, 0156, 0100, 0367, 0216, 0162, 0326, 0133, 0264, 
+  0305, 0242, 0064, 0001, 0065, 0107, 0166, 0146, 0134, 0041, 0005, 0224, 0021, 0352, 0314, 0314, 
+  0073, 0023, 0031, 0216, 0233, 0215, 0275, 0010, 0247, 0145, 0344, 0106, 0324, 0367, 0363, 0106, 
+  0310, 0005, 0075, 0010, 0117, 0141, 0071, 0132, 0016, 0135, 0075, 0245, 0254, 0325, 0313, 0250, 
+  0341, 0122, 0061, 0077, 0323, 0100, 0032, 0046, 0355, 0107, 0172, 0205, 0326, 0132, 0356, 0202, 
+  0213, 0163, 0112, 0236, 0204, 0302, 0335, 0314, 0135, 0347, 0366, 0137, 0375, 0161, 0354, 0277, 
+  0125, 0274, 0176, 0115, 0117, 0231, 0224, 0333, 0324, 0337, 0153, 0373, 0341, 0067, 0030, 0355, 
+  0252, 0130, 0123, 0245, 0327, 0355, 0301, 0245, 0201, 0364, 0113, 0256, 0337, 0165, 0136, 0366, 
+  0364, 0273, 0027, 0335, 0267, 0346, 0271, 0222, 0066, 0010, 0052, 0242, 0307, 0060, 0340, 0043, 
+  0210, 0311, 0140, 0346, 0130, 0163, 0140, 0205, 0124, 0335, 0046, 0121, 0136, 0064, 0252, 0265, 
+  0142, 0170, 0064, 0103, 0074, 0363, 0074, 0111, 0255, 0114, 0134, 0106, 0322, 0044, 0254, 0151, 
+  0061, 0215, 0262, 0170, 0046, 0373, 0313, 0321, 0241, 0015, 0246, 0164, 0325, 0243, 0067, 0325, 
+  0371, 0137, 0232, 0062, 0126, 0146, 0127, 0072, 0254, 0150, 0046, 0347, 0073, 0177, 0037, 0234, 
+  0357, 0210, 0131, 0337, 0361, 0144, 0142, 0322, 0205, 0337, 0036, 0263, 0373, 0310, 0052, 0075, 
+  0051, 0120, 0016, 0352, 0005, 0305, 0245, 0011, 0163, 0116, 0215, 0351, 0352, 0205, 0131, 0163, 
+  0232, 0224, 0327, 0357, 0347, 0311, 0037, 0145, 0330, 0221, 0023, 0330, 0356, 0112, 0025, 0122, 
+  0355, 0172, 0246, 0063, 0313, 0216, 0167, 0340, 0324, 0233, 0251, 0250, 0136, 0122, 0105, 0265, 
+  0373, 0311, 0177, 0056, 0264, 0032, 0216, 0116, 0141, 0171, 0013, 0302, 0205, 0264, 0143, 0017, 
+  0151, 0306, 0043, 0052, 0357, 0004, 0045, 0267, 0012, 0023, 0043, 0065, 0270, 0136, 0100, 0225, 
+  0345, 0274, 0052, 0262, 0015, 0334, 0141, 0346, 0364, 0242, 0173, 0177, 0313, 0327, 0166, 0153, 
+  0371, 0013, 0074, 0046, 0077, 0006, 0122, 0306, 0240, 0146, 0223, 0123, 0237, 0051, 0224, 0056, 
+  0355, 0336, 0013, 0246, 0147, 0045, 0026, 0304, 0164, 0340, 0310, 0237, 0335, 0225, 0334, 0057, 
+  0004, 0142, 0056, 0021, 0051, 0135, 0051, 0370, 0260, 0104, 0250, 0273, 0262, 0030, 0227, 0011, 
+  0116, 0050, 0311, 0257, 0267, 0033, 0043, 0125, 0167, 0206, 0140, 0271, 0263, 0270, 0172, 0040, 
+  0147, 0361, 0047, 0210, 0065, 0006, 0154, 0306, 0374, 0043, 0063, 0274, 0275, 0277, 0035, 0252, 
+  0367, 0261, 0303, 0057, 0050, 0271, 0166, 0040, 0112, 0276, 0030, 0005, 0303, 0044, 0073, 0332, 
+  0366, 0240, 0341, 0162, 0160, 0024, 0161, 0352, 0101, 0220, 0132, 0275, 0262, 0044, 0172, 0130, 
+  0331, 0221, 0025, 0167, 0115, 0276, 0075, 0251, 0223, 0225, 0260, 0326, 0376, 0252, 0006, 0053, 
+  0215, 0100, 0256, 0251, 0016, 0110, 0053, 0002, 0217, 0165, 0061, 0105, 0063, 0136, 0037, 0227, 
+  0015, 0042, 0007, 0300, 0172, 0201, 0236, 0104, 0207, 0035, 0124, 0333, 0352, 0160, 0160, 0343, 
+  0032, 0327, 0243, 0310, 0050, 0026, 0013, 0075, 0215, 0247, 0134, 0350, 0071, 0176, 0136, 0205, 
+  0236, 0271, 0252, 0110, 0243, 0161, 0150, 0127, 0111, 0105, 0022, 0005, 0246, 0316, 0263, 0037, 
+  0211, 0066, 0253, 0104, 0055, 0102, 0140, 0275, 0361, 0300, 0030, 0330, 0062, 0107, 0330, 0070, 
+  0321, 0046, 0233, 0236, 0104, 0233, 0325, 0343, 0327, 0121, 0375, 0062, 0132, 0265, 0042, 0046, 
+  0346, 0156, 0335, 0062, 0261, 0334, 0030, 0373, 0237, 0131, 0356, 0064, 0375, 0256, 0301, 0162, 
+  0146, 0276, 0161, 0050, 0022, 0223, 0263, 0260, 0343, 0232, 0217, 0062, 0212, 0303, 0147, 0221, 
+  0204, 0240, 0230, 0367, 0013, 0167, 0112, 0333, 0366, 0226, 0375, 0336, 0052, 0355, 0334, 0213, 
+  0077, 0006, 0340, 0315, 0135, 0114, 0052, 0110, 0303, 0262, 0264, 0350, 0015, 0061, 0246, 0201, 
+  0140, 0256, 0364, 0312, 0357, 0361, 0233, 0154, 0074, 0311, 0306, 0147, 0137, 0334, 0044, 0002, 
+  0103, 0274, 0330, 0223, 0012, 0016, 0341, 0026, 0063, 0345, 0226, 0063, 0261, 0236, 0023, 0137, 
+  0321, 0201, 0313, 0204, 0157, 0142, 0071, 0251, 0036, 0336, 0111, 0307, 0107, 0162, 0175, 0253, 
+  0236, 0274, 0335, 0070, 0274, 0376, 0300, 0147, 0320, 0125, 0364, 0144, 0303, 0356, 0332, 0166, 
+  0302, 0356, 0343, 0247, 0034, 0166, 0237, 0074, 0353, 0373, 0325, 0223, 0003, 0272, 0137, 0135, 
+  0116, 0033, 0310, 0120, 0366, 0100, 0200, 0134, 0006, 0377, 0045, 0002, 0341, 0110, 0101, 0237, 
+  0301, 0300, 0035, 0343, 0325, 0143, 0253, 0337, 0070, 0351, 0237, 0107, 0133, 0060, 0136, 0245, 
+  0111, 0267, 0253, 0144, 0370, 0214, 0325, 0271, 0265, 0222, 0342, 0353, 0003, 0251, 0051, 0336, 
+  0214, 0052, 0212, 0150, 0366, 0103, 0252, 0330, 0236, 0034, 0210, 0172, 0333, 0362, 0341, 0253, 
+  0264, 0073, 0012, 0000, 0033, 0217, 0241, 0020, 0373, 0335, 0070, 0357, 0165, 0206, 0140, 0117, 
+  0061, 0024, 0254, 0157, 0051, 0113, 0175, 0230, 0357, 0006, 0306, 0035, 0331, 0275, 0240, 0075, 
+  0140, 0176, 0017, 0164, 0274, 0320, 0046, 0230, 0115, 0106, 0030, 0311, 0343, 0012, 0066, 0242, 
+  0346, 0334, 0107, 0317, 0150, 0224, 0131, 0322, 0202, 0221, 0010, 0010, 0363, 0237, 0342, 0346, 
+  0206, 0126, 0026, 0271, 0230, 0262, 0071, 0375, 0007, 0221, 0077, 0376, 0007, 0020, 0111, 0140, 
+  0165, 0000, 0050, 0165, 0165, 0141, 0171, 0051, 0157, 0162, 0147, 0057, 0013, 0000, 0000, 0000, 
+  0164, 0150, 0165, 0155, 0142, 0156, 0141, 0151, 0154, 0055, 0146, 0162, 0141, 0155, 0145, 0056, 
+  0160, 0156, 0147, 0000, 0000, 0000, 0000, 0000, 0332, 0001, 0000, 0000, 0000, 0000, 0000, 0000, 
+  0211, 0120, 0116, 0107, 0015, 0012, 0032, 0012, 0000, 0000, 0000, 0015, 0111, 0110, 0104, 0122, 
+  0000, 0000, 0000, 0100, 0000, 0000, 0000, 0100, 0010, 0004, 0000, 0000, 0000, 0000, 0140, 0271, 
+  0125, 0000, 0000, 0000, 0004, 0147, 0101, 0115, 0101, 0000, 0000, 0330, 0353, 0365, 0034, 0024, 
+  0252, 0000, 0000, 0000, 0040, 0143, 0110, 0122, 0115, 0000, 0000, 0172, 0045, 0000, 0000, 0200, 
+  0203, 0000, 0000, 0364, 0045, 0000, 0000, 0204, 0317, 0000, 0000, 0155, 0137, 0000, 0000, 0350, 
+  0154, 0000, 0000, 0074, 0213, 0000, 0000, 0033, 0130, 0325, 0222, 0146, 0223, 0000, 0000, 0001, 
+  0145, 0111, 0104, 0101, 0124, 0170, 0001, 0355, 0231, 0131, 0152, 0303, 0100, 0014, 0206, 0277, 
+  0231, 0354, 0173, 0356, 0060, 0357, 0335, 0017, 0222, 0213, 0064, 0217, 0211, 0175, 0266, 0036, 
+  0116, 0065, 0002, 0201, 0140, 0336, 0255, 0202, 0312, 0217, 0166, 0143, 0176, 0344, 0131, 0061, 
+  0124, 0026, 0154, 0071, 0162, 0122, 0034, 0061, 0175, 0124, 0075, 0211, 0125, 0024, 0336, 0063, 
+  0153, 0332, 0236, 0166, 0031, 0023, 0127, 0263, 0334, 0226, 0005, 0105, 0200, 0045, 0022, 0202, 
+  0306, 0205, 0245, 0000, 0133, 0344, 0147, 0166, 0040, 0334, 0150, 0154, 0005, 0070, 0062, 0045, 
+  0204, 0071, 0241, 0004, 0356, 0274, 0161, 0244, 0306, 0021, 0030, 0370, 0104, 0011, 0234, 0302, 
+  0010, 0174, 0105, 0166, 0300, 0010, 0224, 0304, 0035, 0030, 0255, 0003, 0341, 0203, 0060, 0162, 
+  0014, 0234, 0042, 0147, 0301, 0250, 0004, 0112, 0044, 0201, 0117, 0045, 0020, 0074, 0010, 0153, 
+  0362, 0101, 0030, 0117, 0200, 0362, 0337, 0201, 0344, 0013, 0321, 0061, 0176, 0045, 0014, 0337, 
+  0013, 0112, 0336, 0275, 0300, 0072, 0220, 0372, 0120, 0372, 0031, 0073, 0010, 0307, 0370, 0117, 
+  0360, 0025, 0337, 0201, 0340, 0061, 0140, 0004, 0222, 0137, 0114, 0242, 0017, 0245, 0231, 0067, 
+  0243, 0361, 0317, 0254, 0204, 0071, 0057, 0046, 0326, 0201, 0370, 0355, 0270, 0246, 0046, 0140, 
+  0143, 0040, 0363, 0365, 0374, 0030, 0277, 0020, 0145, 0076, 0226, 0373, 0355, 0070, 0361, 0335, 
+  0060, 0172, 0026, 0304, 0137, 0317, 0323, 0137, 0114, 0162, 0037, 0112, 0375, 0047, 0310, 0173, 
+  0061, 0211, 0337, 0214, 0154, 0020, 0316, 0016, 0204, 0247, 0133, 0210, 0102, 0360, 0155, 0377, 
+  0015, 0167, 0064, 0156, 0334, 0171, 0062, 0062, 0250, 0050, 0314, 0353, 0342, 0336, 0357, 0063, 
+  0243, 0323, 0335, 0033, 0325, 0336, 0271, 0321, 0330, 0121, 0140, 0311, 0225, 0306, 0033, 0237, 
+  0174, 0251, 0114, 0332, 0371, 0146, 0055, 0257, 0265, 0256, 0142, 0125, 0127, 0351, 0252, 0246, 
+  0125, 0170, 0245, 0161, 0145, 0051, 0100, 0141, 0311, 0226, 0243, 0242, 0373, 0373, 0255, 0272, 
+  0363, 0234, 0365, 0117, 0373, 0232, 0345, 0373, 0167, 0130, 0145, 0313, 0222, 0052, 0040, 0120, 
+  0004, 0052, 0105, 0105, 0065, 0125, 0121, 0234, 0070, 0370, 0272, 0152, 0213, 0373, 0234, 0305, 
+  0375, 0033, 0024, 0202, 0360, 0013, 0333, 0245, 0223, 0145, 0342, 0165, 0274, 0152, 0000, 0000, 
+  0000, 0000, 0111, 0105, 0116, 0104, 0256, 0102, 0140, 0202, 0000, 0000, 0050, 0165, 0165, 0141, 
+  0171, 0051, 0057, 0000, 0001, 0000, 0000, 0000, 0145, 0157, 0155, 0055, 0151, 0155, 0141, 0147, 
+  0145, 0055, 0160, 0162, 0157, 0160, 0145, 0162, 0164, 0151, 0145, 0163, 0055, 0144, 0151, 0141, 
+  0154, 0157, 0147, 0056, 0165, 0151, 0000, 0000, 0002, 0164, 0000, 0000, 0001, 0000, 0000, 0000, 
+  0170, 0332, 0355, 0135, 0133, 0167, 0233, 0070, 0020, 0176, 0357, 0257, 0140, 0171, 0335, 0103, 
+  0155, 0354, 0244, 0271, 0234, 0204, 0236, 0336, 0267, 0147, 0333, 0156, 0317, 0066, 0273, 0373, 
+  0310, 0221, 0141, 0154, 0253, 0026, 0210, 0225, 0204, 0023, 0357, 0257, 0137, 0011, 0160, 0202, 
+  0157, 0030, 0047, 0004, 0133, 0230, 0247, 0070, 0170, 0004, 0063, 0363, 0215, 0106, 0163, 0101, 
+  0326, 0325, 0353, 0273, 0200, 0030, 0123, 0140, 0034, 0323, 0360, 0332, 0264, 0137, 0166, 0115, 
+  0003, 0102, 0217, 0372, 0070, 0034, 0135, 0233, 0177, 0335, 0174, 0264, 0316, 0315, 0327, 0316, 
+  0213, 0253, 0137, 0054, 0313, 0370, 0004, 0041, 0060, 0044, 0300, 0067, 0156, 0261, 0030, 0033, 
+  0043, 0202, 0174, 0060, 0372, 0057, 0173, 0275, 0227, 0266, 0141, 0131, 0222, 0010, 0207, 0002, 
+  0330, 0020, 0171, 0340, 0134, 0061, 0370, 0067, 0306, 0014, 0270, 0101, 0360, 0340, 0332, 0034, 
+  0211, 0311, 0257, 0346, 0303, 0123, 0324, 0030, 0263, 0343, 0134, 0011, 0010, 0042, 0042, 0157, 
+  0150, 0170, 0004, 0161, 0176, 0155, 0176, 0240, 0301, 0167, 0106, 0043, 0140, 0002, 0003, 0177, 
+  0217, 0021, 0241, 0043, 0323, 0210, 0020, 0203, 0120, 0134, 0233, 0237, 0304, 0044, 0273, 0344, 
+  0134, 0105, 0051, 0325, 0314, 0010, 0121, 0000, 0327, 0246, 0207, 0102, 0167, 0110, 0275, 0230, 
+  0233, 0316, 0107, 0104, 0070, 0134, 0165, 0346, 0004, 0053, 0244, 0003, 0312, 0174, 0140, 0356, 
+  0055, 0366, 0305, 0330, 0164, 0116, 0013, 0050, 0005, 0026, 0004, 0114, 0103, 0060, 0024, 0162, 
+  0311, 0044, 0032, 0020, 0171, 0161, 0006, 0362, 0031, 0237, 0003, 0064, 0002, 0343, 0201, 0323, 
+  0202, 0233, 0140, 0217, 0206, 0256, 0372, 0150, 0072, 0122, 0007, 0126, 0124, 0146, 0214, 0230, 
+  0105, 0340, 0216, 0245, 0056, 0115, 0307, 0117, 0004, 0316, 0323, 0172, 0143, 0114, 0174, 0071, 
+  0204, 0110, 0055, 0217, 0051, 0221, 0262, 0110, 0075, 0166, 0262, 0253, 0311, 0037, 0043, 0101, 
+  0041, 0104, 0304, 0112, 0376, 0275, 0066, 0247, 0003, 0172, 0047, 0165, 0106, 0007, 0077, 0301, 
+  0023, 0163, 0125, 0113, 0155, 0276, 0225, 0227, 0015, 0054, 0011, 0260, 0222, 0047, 0307, 0233, 
+  0225, 0076, 0326, 0312, 0006, 0056, 0261, 0067, 0305, 0034, 0113, 0135, 0230, 0316, 0015, 0213, 
+  0213, 0064, 0275, 0003, 0050, 0224, 0141, 0011, 0061, 0022, 0322, 0070, 0114, 0147, 0252, 0230, 
+  0360, 0020, 0051, 0240, 0347, 0021, 0362, 0244, 0175, 0232, 0116, 0157, 0105, 0065, 0053, 0322, 
+  0043, 0117, 0335, 0326, 0225, 0106, 0204, 0326, 0052, 0041, 0026, 0202, 0206, 0367, 0252, 0310, 
+  0044, 0317, 0015, 0262, 0153, 0321, 0000, 0101, 0063, 0032, 0013, 0227, 0213, 0231, 0272, 0057, 
+  0204, 0376, 0032, 0314, 0067, 0360, 0236, 0062, 0036, 0061, 0230, 0142, 0032, 0163, 0167, 0220, 
+  0136, 0254, 0202, 0351, 0022, 0224, 0076, 0014, 0121, 0114, 0304, 0126, 0132, 0006, 0036, 0340, 
+  0051, 0360, 0207, 0001, 0053, 0032, 0331, 0050, 0345, 0034, 0233, 0261, 0064, 0307, 0136, 0075, 
+  0160, 0214, 0021, 0301, 0043, 0251, 0104, 0017, 0224, 0065, 0025, 0020, 0116, 0313, 0022, 0026, 
+  0230, 0354, 0032, 0231, 0023, 0017, 0223, 0233, 0234, 0275, 0132, 0244, 0346, 0202, 0172, 0223, 
+  0324, 0121, 0215, 0250, 0065, 0100, 0336, 0044, 0117, 0334, 0111, 0271, 0224, 0243, 0344, 0027, 
+  0122, 0224, 0225, 0341, 0160, 0027, 0241, 0320, 0337, 0376, 0230, 0041, 0046, 0144, 0073, 0125, 
+  0104, 0071, 0116, 0035, 0102, 0167, 0201, 0213, 0373, 0247, 0057, 0070, 0275, 0065, 0072, 0374, 
+  0202, 0006, 0100, 0122, 0035, 0022, 0365, 0361, 0244, 0137, 0323, 0114, 0116, 0036, 0273, 0146, 
+  0331, 0160, 0277, 0147, 0163, 0264, 0140, 0164, 0314, 0301, 0215, 0103, 0351, 0325, 0011, 0016, 
+  0327, 0260, 0265, 0067, 0014, 0354, 0142, 0014, 0356, 0371, 0132, 0271, 0240, 0211, 0261, 0344, 
+  0135, 0151, 0010, 0167, 0242, 0351, 0156, 0264, 0173, 0224, 0156, 0324, 0336, 0203, 0033, 0035, 
+  0122, 0166, 0213, 0230, 0337, 0050, 0117, 0332, 0333, 0267, 0047, 0375, 0046, 0247, 0150, 0353, 
+  0105, 0367, 0306, 0150, 0031, 0057, 0352, 0021, 0052, 0121, 0330, 0344, 0106, 0123, 0154, 0223, 
+  0071, 0222, 0020, 0026, 0371, 0206, 0103, 0367, 0270, 0153, 0214, 0057, 0163, 0001, 0007, 0143, 
+  0170, 0275, 0222, 0206, 0127, 0023, 0137, 0362, 0051, 0256, 0312, 0162, 0127, 0062, 0235, 0252, 
+  0075, 0327, 0067, 0052, 0140, 0100, 0351, 0044, 0133, 0330, 0347, 0377, 0325, 0140, 0143, 0005, 
+  0165, 0006, 0056, 0227, 0072, 0104, 0346, 0213, 0305, 0055, 0026, 0336, 0330, 0212, 0222, 0205, 
+  0152, 0054, 0225, 0114, 0200, 0111, 0175, 0323, 0300, 0175, 0310, 0307, 0335, 0064, 0053, 0165, 
+  0025, 0221, 0233, 0016, 0060, 0215, 0124, 0326, 0015, 0065, 0023, 0176, 0213, 0242, 0010, 0022, 
+  0221, 0125, 0235, 0145, 0153, 0114, 0060, 0112, 0052, 0073, 0304, 0175, 0266, 0204, 0177, 0053, 
+  0007, 0252, 0326, 0320, 0073, 0253, 0145, 0135, 0131, 0204, 0306, 0356, 0076, 0245, 0060, 0121, 
+  0042, 0362, 0020, 0343, 0070, 0030, 0204, 0010, 0023, 0067, 0211, 0101, 0126, 0105, 0114, 0030, 
+  0161, 0125, 0301, 0014, 0270, 0120, 0014, 0025, 0161, 0064, 0006, 0074, 0032, 0213, 0262, 0324, 
+  0317, 0033, 0335, 0004, 0230, 0163, 0071, 0015, 0255, 0104, 0056, 0035, 0002, 0234, 0212, 0371, 
+  0332, 0242, 0324, 0247, 0047, 0045, 0371, 0220, 0335, 0276, 0070, 0264, 0311, 0161, 0037, 0213, 
+  0237, 0355, 0076, 0323, 0057, 0016, 0273, 0256, 0170, 0132, 0106, 0242, 0345, 0260, 0270, 0377, 
+  0252, 0326, 0244, 0212, 0013, 0304, 0212, 0202, 0340, 0000, 0261, 0021, 0016, 0135, 0101, 0043, 
+  0323, 0071, 0337, 0116, 0067, 0240, 0062, 0122, 0013, 0212, 0111, 0067, 0107, 0344, 0337, 0344, 
+  0367, 0227, 0005, 0043, 0177, 0306, 0134, 0340, 0341, 0314, 0164, 0230, 0162, 0137, 0171, 0102, 
+  0044, 0004, 0303, 0062, 0114, 0004, 0236, 0373, 0074, 0367, 0214, 0211, 0263, 0063, 0015, 0231, 
+  0036, 0306, 0211, 0155, 0022, 0137, 0055, 0147, 0235, 0374, 0030, 0335, 0223, 0251, 0376, 0331, 
+  0361, 0132, 0315, 0077, 0312, 0313, 0134, 0066, 0302, 0032, 0354, 0212, 0254, 0341, 0374, 0170, 
+  0255, 0341, 0267, 0004, 0337, 0146, 0230, 0103, 0257, 0042, 0163, 0270, 0070, 0136, 0163, 0270, 
+  0221, 0011, 0142, 0063, 0214, 0241, 0137, 0121, 0331, 0255, 0173, 0274, 0306, 0360, 0166, 0046, 
+  0041, 0154, 0206, 0065, 0234, 0124, 0143, 0015, 0147, 0375, 0343, 0265, 0206, 0057, 0324, 0113, 
+  0202, 0372, 0146, 0030, 0304, 0351, 0141, 0025, 0347, 0052, 0313, 0132, 0125, 0242, 0327, 0357, 
+  0066, 0053, 0321, 0123, 0303, 0335, 0254, 0170, 0175, 0240, 0263, 0357, 0242, 0374, 0354, 0073, 
+  0053, 0122, 0021, 0020, 0251, 0005, 0264, 0126, 0040, 0215, 0163, 0256, 0264, 0330, 0326, 0042, 
+  0250, 0157, 0236, 0224, 0125, 0100, 0133, 0010, 0365, 0315, 0155, 0222, 0067, 0034, 0133, 0000, 
+  0365, 0315, 0107, 0006, 0052, 0034, 0157, 0021, 0324, 0055, 0207, 0310, 0367, 0347, 0207, 0311, 
+  0313, 0303, 0333, 0032, 0364, 0351, 0327, 0265, 0166, 0347, 0127, 0073, 0356, 0313, 0003, 0026, 
+  0032, 0250, 0036, 0301, 0336, 0004, 0374, 0134, 0363, 0064, 0362, 0335, 0005, 0341, 0334, 0214, 
+  0304, 0365, 0006, 0273, 0265, 0115, 0217, 0044, 0043, 0050, 0335, 0306, 0262, 0365, 0146, 0153, 
+  0361, 0055, 0171, 0265, 0006, 0311, 0225, 0010, 0015, 0314, 0062, 0245, 0227, 0075, 0277, 0360, 
+  0224, 0356, 0274, 0040, 0073, 0371, 0036, 0071, 0336, 0335, 0140, 0170, 0217, 0110, 0346, 0002, 
+  0020, 0310, 0227, 0074, 0271, 0007, 0263, 0047, 0240, 0334, 0213, 0216, 0275, 0006, 0165, 0115, 
+  0153, 0152, 0016, 0074, 0135, 0363, 0011, 0263, 0166, 0003, 0133, 0274, 0347, 0207, 0325, 0236, 
+  0331, 0354, 0060, 0336, 0050, 0262, 0230, 0201, 0361, 0267, 0252, 0170, 0135, 0266, 0015, 0327, 
+  0034, 0206, 0175, 0115, 0060, 0374, 0160, 0047, 0145, 0127, 0030, 0336, 0340, 0000, 0332, 0056, 
+  0151, 0016, 0302, 0213, 0127, 0232, 0100, 0370, 0221, 0112, 0157, 0144, 0174, 0201, 0160, 0324, 
+  0224, 0076, 0167, 0105, 0215, 0315, 0213, 0123, 0135, 0020, 0224, 0042, 0214, 0333, 0066, 0144, 
+  0036, 0272, 0023, 0115, 0240, 0373, 0374, 0343, 0017, 0343, 0107, 0004, 0340, 0033, 0177, 0312, 
+  0370, 0040, 0034, 0265, 0355, 0303, 0074, 0212, 0272, 0254, 0202, 0137, 0101, 0000, 0223, 0042, 
+  0032, 0137, 0251, 0017, 0107, 0321, 0360, 0053, 0015, 0141, 0117, 0023, 0010, 0337, 0311, 0357, 
+  0031, 0112, 0000, 0044, 0107, 0366, 0222, 0340, 0253, 0212, 0240, 0266, 0065, 0201, 0372, 0075, 
+  0022, 0320, 0151, 0116, 0274, 0172, 0166, 0120, 0025, 0057, 0344, 0373, 0253, 0251, 0353, 0263, 
+  0265, 0357, 0357, 0202, 0310, 0075, 0370, 0037, 0200, 0170, 0124, 0026, 0157, 0333, 0332, 0114, 
+  0047, 0340, 0036, 0303, 0121, 0163, 0336, 0165, 0251, 0050, 0207, 0267, 0355, 0256, 0046, 0010, 
+  0066, 0353, 0125, 0045, 0273, 0052, 0370, 0164, 0011, 0135, 0176, 0207, 0331, 0055, 0145, 0076, 
+  0157, 0223, 0367, 0005, 0370, 0164, 0111, 0036, 0336, 0304, 0142, 0114, 0131, 0233, 0276, 0057, 
+  0200, 0247, 0113, 0376, 0376, 0216, 0106, 0063, 0326, 0234, 0055, 0001, 0047, 0155, 0123, 0267, 
+  0306, 0055, 0223, 0252, 0005, 0165, 0322, 0325, 0251, 0137, 0326, 0153, 0126, 0244, 0015, 0167, 
+  0170, 0350, 0242, 0254, 0015, 0165, 0200, 0257, 0012, 0251, 0237, 0151, 0010, 0020, 0233, 0304, 
+  0321, 0326, 0247, 0157, 0256, 0113, 0354, 0360, 0256, 0320, 0362, 0264, 0041, 0004, 0107, 0034, 
+  0377, 0267, 0372, 0033, 0010, 0032, 0307, 0346, 0011, 0346, 0220, 0265, 0255, 0364, 0306, 0134, 
+  0157, 0050, 0355, 0152, 0240, 0034, 0252, 0366, 0125, 0213, 0243, 0316, 0001, 0173, 0212, 0243, 
+  0152, 0142, 0265, 0070, 0352, 0034, 0273, 0047, 0070, 0142, 0116, 0133, 0024, 0165, 0156, 0275, 
+  0045, 0050, 0006, 0131, 0107, 0253, 0205, 0122, 0347, 0026, 0134, 0012, 0245, 0152, 0151, 0265, 
+  0070, 0352, 0334, 0137, 0113, 0160, 0364, 0221, 0150, 0343, 0325, 0266, 0317, 0266, 0317, 0076, 
+  0133, 0215, 0346, 0127, 0133, 0015, 0100, 0211, 0346, 0077, 0264, 0260, 0332, 0052, 0300, 0121, 
+  0124, 0001, 0024, 0352, 0044, 0153, 0173, 0265, 0116, 0125, 0347, 0042, 0200, 0102, 0162, 0222, 
+  0165, 0300, 0132, 0044, 0165, 0056, 0003, 0050, 0044, 0075, 0006, 0110, 0120, 0326, 0002, 0251, 
+  0163, 0035, 0100, 0001, 0231, 0054, 0100, 0355, 0204, 0154, 0173, 0171, 0015, 0333, 0240, 0251, 
+  0107, 0213, 0361, 0103, 0302, 0015, 0260, 0245, 0175, 0221, 0276, 0374, 0200, 0011, 0167, 0141, 
+  0376, 0365, 0163, 0154, 0225, 0056, 0161, 0372, 0123, 0272, 0257, 0165, 0356, 0033, 0212, 0134, 
+  0311, 0263, 0160, 0374, 0370, 0075, 0256, 0357, 0123, 0166, 0252, 0354, 0365, 0057, 0154, 0024, 
+  0017, 0251, 0012, 0337, 0057, 0057, 0063, 0161, 0227, 0166, 0214, 0247, 0145, 0200, 0114, 0043, 
+  0352, 0370, 0247, 0251, 0072, 0350, 0154, 0373, 0226, 0161, 0064, 0024, 0352, 0016, 0112, 0202, 
+  0215, 0333, 0307, 0367, 0234, 0306, 0366, 0253, 0375, 0051, 0366, 0247, 0316, 0346, 0335, 0002, 
+  0324, 0035, 0367, 0151, 0357, 0173, 0243, 0366, 0327, 0314, 0035, 0354, 0264, 0112, 0155, 0320, 
+  0110, 0075, 0373, 0271, 0347, 0066, 0177, 0150, 0373, 0272, 0327, 0373, 0270, 0035, 0164, 0331, 
+  0253, 0322, 0272, 0002, 0377, 0136, 0121, 0365, 0205, 0135, 0073, 0371, 0312, 0307, 0152, 0346, 
+  0051, 0126, 0246, 0313, 0057, 0076, 0244, 0307, 0371, 0131, 0267, 0330, 0037, 0201, 0340, 0113, 
+  0377, 0033, 0014, 0170, 0104, 0103, 0056, 0237, 0320, 0065, 0235, 0245, 0163, 0364, 0344, 0172, 
+  0222, 0247, 0055, 0034, 0232, 0073, 0067, 0252, 0364, 0060, 0353, 0314, 0164, 0362, 0047, 0245, 
+  0254, 0014, 0354, 0054, 0363, 0236, 0034, 0021, 0050, 0315, 0127, 0131, 0351, 0134, 0313, 0064, 
+  0260, 0066, 0234, 0341, 0230, 0254, 0103, 0331, 0220, 0316, 0374, 0270, 0115, 0371, 0361, 0341, 
+  0244, 0316, 0027, 0377, 0003, 0307, 0136, 0225, 0153, 0000, 0050, 0165, 0165, 0141, 0171, 0051, 
+  0145, 0157, 0155, 0056, 0141, 0142, 0157, 0165, 0164, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 
+  0145, 0010, 0000, 0000, 0001, 0000, 0000, 0000, 0170, 0332, 0225, 0125, 0113, 0222, 0334, 0066, 
+  0014, 0335, 0373, 0024, 0334, 0160, 0225, 0152, 0371, 0273, 0210, 0063, 0262, 0253, 0172, 0074, 
+  0143, 0273, 0342, 0231, 0111, 0147, 0172, 0342, 0311, 0247, 0262, 0200, 0044, 0110, 0342, 0210, 
+  0044, 0024, 0176, 0372, 0267, 0317, 0101, 0122, 0225, 0063, 0344, 0002, 0316, 0301, 0002, 0112, 
+  0152, 0133, 0135, 0345, 0115, 0026, 0335, 0004, 0330, 0257, 0111, 0000, 0017, 0170, 0374, 0155, 
+  0131, 0120, 0014, 0277, 0077, 0132, 0306, 0320, 0222, 0363, 0257, 0226, 0025, 0030, 0161, 0351, 
+  0052, 0003, 0126, 0344, 0055, 0166, 0250, 0045, 0270, 0262, 0325, 0312, 0306, 0135, 0246, 0154, 
+  0115, 0257, 0317, 0226, 0235, 0157, 0141, 0057, 0336, 0305, 0076, 0200, 0310, 0073, 0025, 0100, 
+  0153, 0345, 0145, 0143, 0100, 0351, 0254, 0044, 0303, 0010, 0215, 0073, 0260, 0025, 0072, 0261, 
+  0332, 0267, 0240, 0151, 0043, 0162, 0350, 0107, 0353, 0053, 0060, 0207, 0342, 0226, 0174, 0240, 
+  0115, 0360, 0310, 0310, 0200, 0301, 0221, 0121, 0226, 0144, 0203, 0066, 0020, 0145, 0344, 0232, 
+  0021, 0213, 0112, 0254, 0311, 0121, 0247, 0070, 0064, 0117, 0056, 0203, 0141, 0117, 0032, 0244, 
+  0255, 0313, 0134, 0234, 0100, 0173, 0161, 0013, 0125, 0067, 0334, 0071, 0270, 0231, 0033, 0334, 
+  0223, 0213, 0235, 0352, 0304, 0005, 0156, 0320, 0172, 0106, 0261, 0043, 0033, 0113, 0006, 0307, 
+  0233, 0316, 0301, 0007, 0205, 0126, 0334, 0120, 0211, 0216, 0023, 0154, 0241, 0102, 0357, 0345, 
+  0270, 0144, 0026, 0003, 0103, 0036, 0076, 0375, 0343, 0254, 0270, 0307, 0202, 0123, 0314, 0213, 
+  0007, 0102, 0147, 0263, 0155, 0362, 0136, 0276, 0220, 0141, 0101, 0226, 0313, 0205, 0131, 0205, 
+  0214, 0044, 0247, 0274, 0270, 0154, 0070, 0154, 0016, 0010, 0207, 0125, 0216, 0305, 0034, 0042, 
+  0171, 0243, 0041, 0126, 0212, 0304, 0032, 0140, 0203, 0125, 0272, 0256, 0364, 0223, 0051, 0125, 
+  0003, 0132, 0301, 0210, 0273, 0300, 0002, 0234, 0157, 0025, 0347, 0266, 0027, 0171, 0065, 0171, 
+  0156, 0036, 0367, 0045, 0203, 0275, 0130, 0142, 0241, 0104, 0036, 0075, 0272, 0247, 0057, 0236, 
+  0311, 0226, 0302, 0227, 0254, 0057, 0015, 0223, 0032, 0121, 0213, 0025, 0224, 0174, 0053, 0207, 
+  0063, 0155, 0314, 0117, 0171, 0213, 0114, 0233, 0052, 0111, 0134, 0243, 0205, 0305, 0217, 0121, 
+  0331, 0200, 0216, 0104, 0136, 0117, 0373, 0214, 0215, 0107, 0244, 0126, 0073, 0161, 0253, 0220, 
+  0017, 0141, 0102, 0152, 0067, 0132, 0363, 0303, 0336, 0101, 0301, 0273, 0132, 0274, 0041, 0147, 
+  0024, 0272, 0305, 0262, 0256, 0065, 0226, 0035, 0227, 0114, 0077, 0051, 0073, 0254, 0122, 0230, 
+  0236, 0352, 0060, 0347, 0346, 0173, 0330, 0060, 0124, 0254, 0077, 0375, 0145, 0313, 0026, 0017, 
+  0042, 0177, 0360, 0060, 0130, 0222, 0353, 0337, 0025, 0072, 0342, 0204, 0113, 0344, 0275, 0125, 
+  0266, 0103, 0206, 0260, 0055, 0203, 0123, 0177, 0214, 0364, 0134, 0201, 0077, 0150, 0022, 0134, 
+  0173, 0142, 0176, 0025, 0030, 0317, 0231, 0306, 0371, 0045, 0127, 0020, 0035, 0067, 0227, 0270, 
+  0201, 0076, 0025, 0055, 0017, 0140, 0172, 0015, 0126, 0326, 0016, 0061, 0253, 0035, 0003, 0120, 
+  0065, 0255, 0130, 0227, 0024, 0202, 0310, 0165, 0162, 0236, 0076, 0173, 0076, 0360, 0046, 0033, 
+  0242, 0106, 0343, 0354, 0254, 0130, 0362, 0021, 0267, 0124, 0266, 0314, 0236, 0116, 0316, 0011, 
+  0055, 0127, 0061, 0034, 0304, 0365, 0256, 0174, 0276, 0053, 0112, 0255, 0123, 0277, 0104, 0127, 
+  0176, 0053, 0335, 0041, 0213, 0126, 0055, 0072, 0160, 0332, 0273, 0330, 0216, 0335, 0162, 0315, 
+  0243, 0306, 0345, 0272, 0120, 0017, 0235, 0017, 0251, 0031, 0314, 0260, 0221, 0125, 0373, 0301, 
+  0237, 0147, 0300, 0320, 0300, 0163, 0160, 0016, 0121, 0253, 0146, 0000, 0262, 0313, 0174, 0033, 
+  0134, 0120, 0275, 0030, 0073, 0154, 0270, 0177, 0002, 0336, 0053, 0323, 0073, 0156, 0340, 0317, 
+  0120, 0003, 0001, 0027, 0251, 0244, 0201, 0372, 0011, 0251, 0070, 0005, 0276, 0376, 0032, 0261, 
+  0113, 0070, 0223, 0326, 0057, 0174, 0137, 0053, 0056, 0365, 0221, 0321, 0334, 0260, 0227, 0065, 
+  0243, 0047, 0053, 0360, 0013, 0256, 0374, 0141, 0213, 0256, 0013, 0010, 0146, 0110, 0146, 0005, 
+  0105, 0042, 0201, 0063, 0140, 0010, 0347, 0342, 0113, 0332, 0112, 0236, 0006, 0214, 0375, 0110, 
+  0323, 0012, 0150, 0144, 0011, 0131, 0077, 0104, 0336, 0027, 0243, 0045, 0073, 0140, 0072, 0076, 
+  0047, 0272, 0102, 0307, 0163, 0225, 0210, 0354, 0047, 0153, 0136, 0206, 0125, 0253, 0264, 0352, 
+  0305, 0107, 0126, 0253, 0367, 0104, 0065, 0203, 0066, 0140, 0133, 0266, 0346, 0024, 0254, 0024, 
+  0005, 0047, 0056, 0334, 0277, 0177, 0162, 0245, 0372, 0344, 0360, 0170, 0065, 0363, 0143, 0156, 
+  0211, 0117, 0016, 0342, 0074, 0076, 0210, 0334, 0015, 0166, 0126, 0304, 0207, 0023, 0104, 0364, 
+  0236, 0243, 0023, 0357, 0131, 0124, 0170, 0002, 0367, 0321, 0364, 0321, 0203, 0041, 0333, 0304, 
+  0223, 0200, 0326, 0120, 0327, 0052, 0264, 0242, 0015, 0241, 0367, 0337, 0075, 0176, 0334, 0260, 
+  0023, 0213, 0364, 0333, 0343, 0351, 0047, 0206, 0014, 0322, 0270, 0336, 0042, 0167, 0077, 0367, 
+  0247, 0255, 0225, 0123, 0047, 0063, 0060, 0366, 0335, 0071, 0150, 0213, 0254, 0005, 0214, 0361, 
+  0305, 0150, 0177, 0205, 0265, 0243, 0042, 0116, 0002, 0371, 0165, 0141, 0134, 0007, 0144, 0151, 
+  0375, 0240, 0225, 0341, 0321, 0300, 0255, 0357, 0022, 0060, 0355, 0235, 0150, 0054, 0243, 0152, 
+  0260, 0044, 0076, 0200, 0203, 0036, 0203, 0117, 0223, 0341, 0307, 0075, 0046, 0345, 0270, 0067, 
+  0205, 0030, 0130, 0076, 0305, 0257, 0350, 0313, 0166, 0000, 0155, 0360, 0220, 0354, 0147, 0363, 
+  0064, 0356, 0224, 0021, 0357, 0320, 0045, 0362, 0203, 0062, 0337, 0244, 0330, 0213, 0330, 0160, 
+  0271, 0322, 0336, 0330, 0003, 0014, 0061, 0342, 0374, 0323, 0337, 0251, 0040, 0171, 0372, 0247, 
+  0054, 0040, 0051, 0115, 0030, 0043, 0272, 0163, 0312, 0266, 0142, 0311, 0237, 0233, 0206, 0112, 
+  0326, 0352, 0260, 0175, 0372, 0362, 0345, 0223, 0371, 0045, 0037, 0125, 0031, 0310, 0245, 0230, 
+  0221, 0043, 0331, 0164, 0151, 0225, 0016, 0253, 0026, 0302, 0004, 0320, 0120, 0211, 0037, 0334, 
+  0360, 0012, 0061, 0137, 0076, 0260, 0262, 0332, 0202, 0166, 0103, 0141, 0356, 0111, 0327, 0015, 
+  0330, 0106, 0374, 0244, 0271, 0225, 0123, 0056, 0051, 0112, 0351, 0270, 0354, 0052, 0014, 0155, 
+  0174, 0037, 0305, 0317, 0012, 0050, 0250, 0364, 0040, 0356, 0061, 0050, 0177, 0102, 0325, 0057, 
+  0000, 0351, 0255, 0131, 0243, 0356, 0150, 0253, 0170, 0324, 0363, 0275, 0077, 0332, 0162, 0320, 
+  0267, 0314, 0023, 0117, 0074, 0326, 0234, 0020, 0216, 0111, 0353, 0330, 0141, 0315, 0157, 0134, 
+  0125, 0046, 0301, 0070, 0332, 0262, 0215, 0276, 0375, 0162, 0260, 0303, 0203, 0147, 0335, 0035, 
+  0026, 0071, 0174, 0217, 0177, 0366, 0320, 0251, 0042, 0205, 0131, 0304, 0301, 0234, 0007, 0343, 
+  0043, 0163, 0222, 0157, 0260, 0221, 0176, 0323, 0200, 0101, 0237, 0365, 0372, 0365, 0331, 0243, 
+  0013, 0052, 0243, 0301, 0044, 0344, 0376, 0025, 0277, 0022, 0024, 0304, 0125, 0172, 0166, 0243, 
+  0341, 0047, 0040, 0271, 0122, 0217, 0156, 0126, 0356, 0376, 0317, 0003, 0260, 0216, 0126, 0260, 
+  0146, 0360, 0104, 0356, 0271, 0001, 0214, 0077, 0273, 0136, 0336, 0135, 0212, 0343, 0145, 0020, 
+  0024, 0131, 0161, 0307, 0152, 0160, 0366, 0350, 0077, 0366, 0141, 0020, 0236, 0000, 0050, 0165, 
+  0165, 0141, 0171, 0051, 0145, 0157, 0155, 0056, 0143, 0163, 0163, 0000, 0000, 0000, 0000, 0000, 
+  0250, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0056, 0145, 0157, 0155, 0055, 0167, 0151, 0156, 
+  0144, 0157, 0167, 0040, 0163, 0164, 0141, 0164, 0165, 0163, 0142, 0141, 0162, 0040, 0160, 0162, 
+  0157, 0147, 0162, 0145, 0163, 0163, 0142, 0141, 0162, 0056, 0150, 0157, 0162, 0151, 0172, 0157, 
+  0156, 0164, 0141, 0154, 0054, 0012, 0056, 0145, 0157, 0155, 0055, 0167, 0151, 0156, 0144, 0157, 
+  0167, 0040, 0163, 0164, 0141, 0164, 0165, 0163, 0142, 0141, 0162, 0040, 0160, 0162, 0157, 0147, 
+  0162, 0145, 0163, 0163, 0142, 0141, 0162, 0056, 0150, 0157, 0162, 0151, 0172, 0157, 0156, 0164, 
+  0141, 0154, 0040, 0164, 0162, 0157, 0165, 0147, 0150, 0040, 0173, 0012, 0040, 0040, 0040, 0040, 
+  0155, 0151, 0156, 0055, 0150, 0145, 0151, 0147, 0150, 0164, 0072, 0040, 0061, 0064, 0160, 0170, 
+  0073, 0012, 0175, 0012, 0012, 0043, 0145, 0157, 0155, 0055, 0163, 0151, 0144, 0145, 0142, 0141, 
+  0162, 0055, 0164, 0151, 0164, 0154, 0145, 0040, 0173, 0012, 0011, 0146, 0157, 0156, 0164, 0055, 
+  0167, 0145, 0151, 0147, 0150, 0164, 0072, 0040, 0142, 0157, 0154, 0144, 0073, 0012, 0175, 0012, 
+  0000, 0000, 0050, 0165, 0165, 0141, 0171, 0051, 0145, 0157, 0155, 0057, 0011, 0000, 0000, 0000, 
+  0160, 0151, 0170, 0155, 0141, 0160, 0163, 0057, 0002, 0000, 0000, 0000, 0165, 0151, 0057, 0000, 
+  0004, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0012, 0000, 0000, 0000, 0014, 0000, 0000, 0000, 
+  0005, 0000, 0000, 0000, 0006, 0000, 0000, 0000, 0015, 0000, 0000, 0000, 0010, 0000, 0000, 0000, 
+  0145, 0157, 0155, 0055, 0160, 0162, 0145, 0146, 0145, 0162, 0145, 0156, 0143, 0145, 0163, 0055, 
+  0144, 0151, 0141, 0154, 0157, 0147, 0056, 0165, 0151, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 
+  0146, 0126, 0000, 0000, 0001, 0000, 0000, 0000, 0170, 0332, 0355, 0134, 0333, 0162, 0333, 0066, 
+  0020, 0175, 0357, 0127, 0240, 0174, 0152, 0247, 0245, 0165, 0361, 0045, 0116, 0107, 0126, 0306, 
+  0151, 0235, 0114, 0147, 0222, 0216, 0047, 0166, 0373, 0320, 0027, 0016, 0110, 0256, 0104, 0304, 
+  0040, 0300, 0000, 0140, 0144, 0367, 0353, 0273, 0244, 0044, 0213, 0262, 0044, 0212, 0224, 0165, 
+  0243, 0304, 0170, 0342, 0261, 0250, 0005, 0260, 0213, 0135, 0034, 0234, 0005, 0100, 0164, 0336, 
+  0075, 0206, 0234, 0174, 0007, 0245, 0231, 0024, 0127, 0126, 0353, 0244, 0151, 0021, 0020, 0236, 
+  0364, 0231, 0350, 0137, 0131, 0177, 0337, 0177, 0260, 0057, 0255, 0167, 0335, 0037, 0072, 0077, 
+  0332, 0066, 0371, 0010, 0002, 0024, 0065, 0340, 0223, 0001, 0063, 0001, 0351, 0163, 0352, 0003, 
+  0071, 0075, 0151, 0067, 0117, 0232, 0304, 0266, 0121, 0210, 0011, 0003, 0252, 0107, 0075, 0350, 
+  0166, 0024, 0174, 0213, 0231, 0002, 0115, 0070, 0163, 0257, 0254, 0276, 0171, 0370, 0305, 0232, 
+  0264, 0162, 0172, 0322, 0072, 0263, 0032, 0057, 0205, 0360, 0127, 0004, 0124, 0333, 0050, 0154, 
+  0115, 0153, 0204, 0242, 0322, 0375, 0012, 0236, 0041, 0036, 0247, 0132, 0137, 0131, 0037, 0315, 
+  0303, 0265, 0377, 0065, 0326, 0046, 0004, 0141, 0054, 0302, 0374, 0053, 0213, 0076, 0177, 0156, 
+  0131, 0335, 0116, 0244, 0144, 0004, 0312, 0074, 0021, 0101, 0103, 0300, 0252, 0345, 0000, 0224, 
+  0325, 0155, 0165, 0032, 0343, 0057, 0146, 0104, 0342, 0050, 0112, 0105, 0232, 0315, 0034, 0241, 
+  0357, 0224, 0307, 0140, 0165, 0317, 0163, 0104, 0264, 0201, 0310, 0141, 0302, 0123, 0220, 0352, 
+  0226, 0333, 0146, 0104, 0373, 0060, 0045, 0073, 0325, 0166, 0143, 0150, 0163, 0267, 0143, 0040, 
+  0214, 0070, 0366, 0373, 0330, 0372, 0033, 0031, 0336, 0052, 0350, 0201, 0102, 0107, 0201, 0376, 
+  0203, 0121, 0056, 0373, 0026, 0211, 0050, 0176, 0066, 0151, 0337, 0214, 0036, 0315, 0264, 0347, 
+  0121, 0341, 0364, 0244, 0027, 0153, 0253, 0373, 0201, 0162, 0015, 0071, 0252, 0271, 0122, 0371, 
+  0240, 0234, 0001, 0363, 0115, 0220, 0157, 0260, 0141, 0206, 0203, 0105, 0214, 0242, 0102, 0243, 
+  0226, 0324, 0345, 0370, 0360, 0011, 0260, 0215, 0233, 0047, 0040, 0262, 0107, 0076, 0137, 0337, 
+  0337, 0220, 0214, 0302, 0171, 0165, 0075, 0105, 0340, 0004, 0054, 0351, 0013, 0077, 0265, 0041, 
+  0053, 0353, 0005, 0214, 0373, 0044, 0215, 0061, 0101, 0271, 0235, 0176, 0104, 0227, 0270, 0362, 
+  0321, 0232, 0023, 0037, 0357, 0361, 0161, 0032, 0030, 0303, 0212, 0354, 0104, 0256, 0365, 0252, 
+  0056, 0221, 0212, 0141, 0007, 0123, 0203, 0141, 0151, 0165, 0061, 0076, 0015, 0363, 0050, 0317, 
+  0213, 0204, 0210, 0172, 0070, 0212, 0254, 0156, 0173, 0271, 0025, 0324, 0113, 0252, 0165, 0320, 
+  0205, 0164, 0256, 0061, 0261, 0061, 0122, 0274, 0064, 0051, 0123, 0350, 0165, 0226, 0161, 0372, 
+  0044, 0143, 0343, 0150, 0363, 0204, 0236, 0354, 0202, 0360, 0147, 0024, 0136, 0250, 0323, 0120, 
+  0241, 0000, 0170, 0344, 0270, 0303, 0007, 0163, 0152, 0167, 0201, 0133, 0135, 0034, 0326, 0166, 
+  0042, 0227, 0067, 0274, 0230, 0146, 0156, 0242, 0302, 0275, 0212, 0363, 0364, 0315, 0230, 0126, 
+  0100, 0322, 0207, 0036, 0215, 0271, 0131, 0052, 0253, 0300, 0003, 0366, 0035, 0364, 0244, 0300, 
+  0262, 0176, 0213, 0065, 0140, 0247, 0111, 0357, 0141, 0266, 0356, 0347, 0301, 0213, 0101, 0360, 
+  0200, 0121, 0060, 0123, 0026, 0036, 0043, 0052, 0374, 0345, 0155, 0364, 0030, 0347, 0313, 0245, 
+  0042, 0251, 0331, 0060, 0060, 0247, 0041, 0344, 0271, 0365, 0306, 0310, 0215, 0105, 0274, 0351, 
+  0161, 0211, 0206, 0025, 0160, 0147, 0052, 0130, 0373, 0163, 0243, 0376, 0154, 0345, 0373, 0163, 
+  0333, 0172, 0141, 0053, 0116, 0202, 0322, 0063, 0060, 0261, 0356, 0200, 0374, 0113, 0032, 0160, 
+  0245, 0174, 0030, 0206, 0244, 0030, 0177, 0332, 0102, 0214, 0345, 0114, 0175, 0013, 0107, 0317, 
+  0030, 0231, 0223, 0131, 0346, 0174, 0055, 0112, 0226, 0233, 0240, 0133, 0355, 0115, 0114, 0134, 
+  0255, 0313, 0322, 0306, 0137, 0154, 0305, 0370, 0225, 0055, 0272, 0050, 0142, 0320, 0247, 0024, 
+  0341, 0122, 0223, 0122, 0260, 0333, 0216, 0115, 0001, 0345, 0254, 0217, 0346, 0150, 0103, 0225, 
+  0311, 0235, 0254, 0123, 0355, 0346, 0360, 0255, 0077, 0103, 0344, 0223, 0344, 0106, 0004, 0024, 
+  0151, 0126, 0302, 0050, 0247, 0250, 0026, 0065, 0106, 0061, 0004, 0165, 0320, 0231, 0277, 0107, 
+  0165, 0016, 0200, 0365, 0003, 0044, 0322, 0051, 0277, 0115, 0142, 0213, 0373, 0011, 0351, 0156, 
+  0144, 0313, 0124, 0156, 0106, 0033, 0207, 0145, 0200, 0141, 0351, 0244, 0204, 0053, 0222, 0011, 
+  0215, 0336, 0214, 0067, 0213, 0006, 0323, 0346, 0065, 0231, 0077, 0137, 0023, 0374, 0127, 0145, 
+  0202, 0362, 0173, 0000, 0336, 0024, 0113, 0311, 0364, 0243, 0343, 0045, 0137, 0132, 0045, 0206, 
+  0312, 0135, 0050, 0045, 0246, 0260, 0054, 0031, 0061, 0232, 0014, 0002, 0020, 0344, 0077, 0051, 
+  0103, 0360, 0155, 0007, 0231, 0360, 0126, 0051, 0315, 0152, 0064, 0045, 0026, 0210, 0376, 0234, 
+  0211, 0345, 0232, 0370, 0212, 0016, 0060, 0350, 0174, 0204, 0110, 0043, 0325, 0321, 0062, 0233, 
+  0045, 0275, 0124, 0130, 0255, 0142, 0160, 0003, 0217, 0030, 0164, 0173, 0001, 0067, 0033, 0327, 
+  0344, 0110, 0340, 0046, 0323, 0217, 0153, 0205, 0033, 0046, 0152, 0264, 0071, 0142, 0264, 0151, 
+  0257, 0001, 0155, 0150, 0214, 0135, 0055, 0315, 0316, 0261, 0046, 0321, 0043, 0242, 0176, 0015, 
+  0063, 0257, 0200, 0231, 0211, 0057, 0313, 0243, 0214, 0163, 0215, 0205, 0103, 0314, 0212, 0074, 
+  0222, 0111, 0220, 0152, 0170, 0071, 0302, 0145, 0232, 0147, 0275, 0116, 0367, 0124, 0257, 0327, 
+  0046, 0165, 0013, 0226, 0363, 0053, 0277, 0326, 0320, 0252, 0310, 0132, 0303, 0173, 0364, 0130, 
+  0137, 0311, 0170, 0172, 0021, 0360, 0250, 0327, 0030, 0266, 0343, 0272, 0220, 0252, 0076, 0023, 
+  0016, 0207, 0136, 0262, 0141, 0170, 0121, 0150, 0031, 0257, 0135, 0044, 0022, 0147, 0246, 0042, 
+  0267, 0357, 0170, 0222, 0113, 0125, 0176, 0042, 0272, 0326, 0004, 0155, 0301, 0271, 0210, 0244, 
+  0025, 0374, 0266, 0347, 0123, 0320, 0336, 0116, 0052, 0253, 0222, 0212, 0244, 0323, 0347, 0172, 
+  0162, 0321, 0236, 0316, 0066, 0274, 0260, 0244, 0300, 0342, 0155, 0344, 0011, 0324, 0220, 0324, 
+  0262, 0015, 0272, 0146, 0135, 0213, 0004, 0307, 0241, 0326, 0332, 0330, 0121, 0241, 0331, 0376, 
+  0315, 0001, 0316, 0366, 0227, 0025, 0231, 0355, 0357, 0223, 0107, 0303, 0003, 0046, 0344, 0026, 
+  0053, 0251, 0067, 0026, 0306, 0223, 0376, 0331, 0156, 0123, 0356, 0267, 0165, 0262, 0275, 0042, 
+  0234, 0134, 0036, 0000, 0234, 0174, 0241, 0076, 0223, 0123, 0047, 0067, 0022, 0246, 0026, 0341, 
+  0340, 0002, 0045, 0034, 0225, 0174, 0133, 0226, 0266, 0045, 0025, 0020, 0147, 0124, 0305, 0236, 
+  0363, 0266, 0242, 0270, 0166, 0040, 0113, 0014, 0353, 0200, 0253, 0355, 0234, 0115, 0170, 0155, 
+  0024, 0247, 0134, 0165, 0245, 0360, 0035, 0145, 0035, 0116, 0025, 0322, 0216, 0365, 0206, 0345, 
+  0013, 0361, 0204, 0060, 0107, 0126, 0167, 0026, 0020, 0016, 0052, 0261, 0111, 0243, 0040, 0332, 
+  0203, 0344, 0246, 0124, 0326, 0176, 0261, 0044, 0050, 0050, 0217, 0002, 0372, 0212, 0204, 0051, 
+  0355, 0046, 0322, 0303, 0377, 0131, 0336, 0166, 0255, 0200, 0346, 0235, 0275, 0125, 0175, 0027, 
+  0033, 0305, 0337, 0077, 0065, 0177, 0305, 0237, 0237, 0217, 0057, 0315, 0332, 0170, 0076, 0063, 
+  0203, 0164, 0356, 0163, 0152, 0273, 0022, 0334, 0071, 0356, 0334, 0125, 0270, 0172, 0252, 0256, 
+  0042, 0046, 0266, 0353, 0045, 0205, 0003, 0100, 0206, 0242, 0136, 0234, 0202, 0012, 0222, 0234, 
+  0250, 0105, 0104, 0247, 0256, 0125, 0040, 0347, 0073, 0333, 0142, 0316, 0267, 0370, 0230, 0341, 
+  0077, 0014, 0006, 0245, 0306, 0015, 0126, 0341, 0054, 0350, 0315, 0125, 0367, 0177, 0132, 0307, 
+  0174, 0322, 0266, 0325, 0076, 0304, 0355, 0257, 0323, 0112, 0235, 0265, 0375, 0127, 0312, 0260, 
+  0136, 0012, 0033, 0345, 0226, 0157, 0166, 0273, 0024, 0326, 0072, 0253, 0327, 0302, 0126, 0005, 
+  0322, 0323, 0003, 0200, 0222, 0231, 0375, 0313, 0070, 0322, 0130, 0377, 0012, 0347, 0150, 0156, 
+  0234, 0324, 0127, 0343, 0343, 0172, 0106, 0222, 0036, 0063, 0104, 0173, 0012, 0240, 0076, 0115, 
+  0263, 0017, 0101, 0135, 0163, 0341, 0112, 0160, 0341, 0265, 0100, 0323, 0331, 0041, 0262, 0234, 
+  0363, 0212, 0260, 0234, 0073, 0370, 0026, 0047, 0357, 0154, 0327, 0034, 0147, 0304, 0161, 0056, 
+  0167, 0314, 0161, 0056, 0152, 0216, 0263, 0052, 0220, 0234, 0037, 0000, 0220, 0074, 0133, 0244, 
+  0301, 0223, 0302, 0327, 0116, 0060, 0274, 0375, 0140, 0337, 0266, 0164, 0136, 0306, 0355, 0351, 
+  0305, 0216, 0327, 0054, 0234, 0273, 0001, 0063, 0336, 0350, 0015, 0014, 0102, 0173, 0006, 0162, 
+  0267, 0207, 0312, 0321, 0250, 0120, 0100, 0050, 0005, 0363, 0222, 0045, 0202, 0076, 0040, 0113, 
+  0033, 0173, 0107, 0107, 0323, 0157, 0167, 0124, 0155, 0000, 0335, 0241, 0376, 0131, 0106, 0235, 
+  0265, 0153, 0033, 0373, 0054, 0223, 0073, 0135, 0254, 0156, 0346, 0176, 0227, 0274, 0272, 0071, 
+  0013, 0135, 0107, 0245, 0257, 0102, 0344, 0311, 0211, 0070, 0004, 0305, 0274, 0352, 0034, 0040, 
+  0057, 0074, 0103, 0134, 0356, 0170, 0244, 0215, 0142, 0344, 0010, 0227, 0324, 0267, 0377, 0262, 
+  0010, 0366, 0276, 0057, 0303, 0025, 0136, 0024, 0371, 0222, 0026, 0044, 0172, 0016, 0275, 0253, 
+  0067, 0217, 0052, 0212, 0004, 0063, 0321, 0301, 0245, 0214, 0126, 0210, 0215, 0117, 0130, 0254, 
+  0216, 0214, 0275, 0214, 0214, 0172, 0213, 0260, 0126, 0253, 0044, 0120, 0224, 0333, 0132, 0074, 
+  0337, 0061, 0171, 0270, 0343, 0314, 0007, 0035, 0310, 0162, 0073, 0213, 0013, 0172, 0144, 0243, 
+  0373, 0217, 0021, 0217, 0223, 0003, 0075, 0041, 0025, 0230, 0120, 0050, 0007, 0071, 0217, 0241, 
+  0210, 0055, 0252, 0162, 0073, 0222, 0163, 0055, 0275, 0005, 0252, 0321, 0332, 0333, 0324, 0310, 
+  0317, 0103, 0033, 0347, 0331, 0275, 0037, 0051, 0165, 0341, 0221, 0274, 0104, 0247, 0222, 0003, 
+  0271, 0271, 0266, 0201, 0334, 0136, 0373, 0100, 0176, 0373, 0146, 0307, 0043, 0171, 0030, 0072, 
+  0172, 0305, 0161, 0334, 0136, 0327, 0070, 0336, 0167, 0220, 0037, 0077, 0030, 0136, 0345, 0150, 
+  0017, 0027, 0020, 0364, 0213, 0317, 0104, 0201, 0216, 0244, 0320, 0330, 0202, 0235, 0234, 0171, 
+  0310, 0334, 0266, 0330, 0151, 0114, 0111, 0346, 0024, 0304, 0200, 0310, 0336, 0353, 0067, 0123, 
+  0260, 0361, 0122, 0205, 0364, 0066, 0110, 0014, 0276, 0044, 0306, 0306, 0235, 0045, 0103, 0073, 
+  0232, 0134, 0344, 0151, 0017, 0357, 0241, 0114, 0127, 0170, 0107, 0322, 0215, 0361, 0135, 0245, 
+  0370, 0347, 0344, 0066, 0330, 0037, 0376, 0007, 0137, 0217, 0264, 0316, 0000, 0050, 0165, 0165, 
+  0141, 0171, 0051, 0155, 0141, 0164, 0145, 0057, 0007, 0000, 0000, 0000, 0145, 0157, 0155, 0055, 
+  0165, 0151, 0056, 0170, 0155, 0154, 0000, 0000, 0254, 0020, 0000, 0000, 0001, 0000, 0000, 0000, 
+  0170, 0332, 0355, 0126, 0121, 0117, 0333, 0060, 0020, 0176, 0347, 0127, 0124, 0371, 0001, 0013, 
+  0260, 0115, 0323, 0244, 0122, 0224, 0001, 0005, 0304, 0012, 0025, 0355, 0100, 0332, 0313, 0344, 
+  0246, 0267, 0326, 0232, 0343, 0363, 0142, 0247, 0300, 0176, 0375, 0354, 0070, 0115, 0223, 0324, 
+  0116, 0332, 0111, 0173, 0141, 0173, 0364, 0175, 0337, 0167, 0147, 0337, 0235, 0317, 0356, 0237, 
+  0076, 0047, 0254, 0267, 0202, 0124, 0122, 0344, 0047, 0301, 0321, 0233, 0303, 0340, 0164, 0160, 
+  0320, 0317, 0350, 0240, 0237, 0000, 0317, 0146, 0044, 0355, 0161, 0222, 0300, 0111, 0060, 0042, 
+  0224, 0217, 0264, 0045, 0260, 0100, 0217, 0304, 0052, 0127, 0134, 0047, 0144, 0001, 0205, 0221, 
+  0052, 0110, 0352, 0300, 0235, 0000, 0036, 0204, 0056, 0211, 0101, 0036, 0251, 0132, 0152, 0251, 
+  0140, 0044, 0206, 0045, 0262, 0071, 0254, 0203, 0105, 0102, 0060, 0032, 0023, 0103, 0227, 0275, 
+  0361, 0006, 0066, 0256, 0102, 0343, 0153, 0320, 0227, 0040, 0110, 0112, 0024, 0246, 0241, 0057, 
+  0366, 0204, 0254, 0040, 0150, 0105, 0043, 0151, 0360, 0156, 0117, 0343, 0224, 0162, 0265, 0033, 
+  0165, 0002, 0052, 0222, 0217, 0204, 0061, 0101, 0204, 0335, 0257, 0077, 0061, 0147, 0310, 0225, 
+  0316, 0052, 0345, 0213, 0141, 0171, 0272, 0135, 0066, 0203, 0332, 0263, 0242, 0260, 0265, 0371, 
+  0355, 0074, 0336, 0103, 0014, 0134, 0235, 0143, 0234, 0151, 0137, 0152, 0307, 0323, 0236, 0061, 
+  0224, 0120, 0311, 0164, 0255, 0166, 0027, 0163, 0252, 0134, 0325, 0066, 0366, 0057, 0174, 0216, 
+  0235, 0041, 0014, 0361, 0014, 0305, 0213, 0355, 0233, 0135, 0330, 0103, 0106, 0305, 0025, 0246, 
+  0364, 0227, 0111, 0027, 0013, 0332, 0150, 0017, 0046, 0061, 0261, 0045, 0165, 0372, 0275, 0107, 
+  0105, 0024, 0174, 0074, 0014, 0332, 0011, 0307, 0037, 0016, 0167, 0162, 0067, 0302, 0025, 0114, 
+  0161, 0232, 0022, 0271, 0334, 0211, 0077, 0105, 0144, 0372, 0172, 0171, 0243, 0217, 0123, 0370, 
+  0016, 0051, 0360, 0330, 0026, 0332, 0125, 0214, 0007, 0012, 0117, 0325, 0142, 0330, 0242, 0027, 
+  0216, 0247, 0270, 0130, 0060, 0010, 0152, 0144, 0127, 0114, 0053, 0232, 0350, 0243, 0146, 0322, 
+  0043, 0053, 0101, 0207, 0320, 0266, 0014, 0062, 0006, 0271, 0300, 0045, 0157, 0120, 0134, 0321, 
+  0351, 0034, 0174, 0261, 0055, 0344, 0115, 0251, 0165, 0060, 0314, 0030, 0223, 0161, 0012, 0172, 
+  0332, 0324, 0324, 0025, 0273, 0043, 0052, 0323, 0276, 0345, 0022, 0237, 0032, 0021, 0113, 0163, 
+  0127, 0031, 0015, 0373, 0053, 0142, 0162, 0315, 0203, 0066, 0370, 0056, 0123, 0255, 0370, 0055, 
+  0246, 0211, 0247, 0261, 0327, 0224, 0041, 0125, 0276, 0046, 0270, 0304, 0355, 0026, 0270, 0104, 
+  0335, 0075, 0053, 0212, 0231, 0014, 0052, 0274, 0322, 0026, 0072, 0004, 0267, 0360, 0254, 0252, 
+  0344, 0174, 0335, 0236, 0364, 0113, 0034, 0322, 0124, 0326, 0124, 0326, 0340, 0242, 0176, 0046, 
+  0165, 0146, 0276, 0356, 0362, 0177, 0117, 0364, 0110, 0111, 0252, 0262, 0302, 0322, 0310, 0305, 
+  0246, 0361, 0145, 0376, 0106, 0225, 0202, 0334, 0344, 0174, 0142, 0162, 0344, 0116, 0310, 0157, 
+  0107, 0335, 0143, 0264, 0344, 0036, 0357, 0301, 0175, 0273, 0007, 0367, 0335, 0036, 0334, 0367, 
+  0276, 0106, 0270, 0002, 0046, 0134, 0243, 0331, 0330, 0107, 0204, 0147, 0236, 0026, 0063, 0160, 
+  0064, 0303, 0254, 0332, 0140, 0141, 0361, 0366, 0017, 0372, 0312, 0116, 0214, 0372, 0150, 0011, 
+  0254, 0275, 0346, 0246, 0336, 0136, 0016, 0330, 0325, 0120, 0133, 0264, 0372, 0215, 0362, 0302, 
+  0305, 0215, 0362, 0342, 0233, 0033, 0345, 0245, 0024, 0067, 0252, 0165, 0067, 0133, 0217, 0100, 
+  0013, 0303, 0276, 0043, 0141, 0221, 0257, 0146, 0342, 0066, 0163, 0250, 0065, 0205, 0345, 0365, 
+  0371, 0363, 0364, 0072, 0040, 0327, 0125, 0173, 0165, 0231, 0357, 0074, 0234, 0343, 0025, 0152, 
+  0325, 0214, 0111, 0046, 0241, 0366, 0026, 0154, 0212, 0053, 0120, 0144, 0142, 0175, 0047, 0226, 
+  0131, 0062, 0343, 0204, 0262, 0261, 0061, 0006, 0377, 0306, 0137, 0167, 0377, 0137, 0334, 0076, 
+  0337, 0043, 0307, 0077, 0367, 0357, 0374, 0266, 0303, 0274, 0220, 0365, 0172, 0232, 0136, 0371, 
+  0137, 0312, 0127, 0121, 0312, 0142, 0326, 0332, 0152, 0326, 0376, 0004, 0153, 0153, 0144, 0147, 
+  0101, 0367, 0027, 0175, 0355, 0236, 0304, 0061, 0060, 0310, 0217, 0133, 0004, 0061, 0233, 0111, 
+  0221, 0135, 0374, 0324, 0017, 0154, 0144, 0320, 0115, 0244, 0052, 0144, 0234, 0170, 0305, 0067, 
+  0343, 0150, 0076, 0167, 0213, 0157, 0204, 0206, 0072, 0304, 0223, 0154, 0346, 0023, 0153, 0310, 
+  0055, 0376, 0104, 0342, 0037, 0023, 0241, 0133, 0264, 0241, 0054, 0355, 0156, 0331, 0271, 0136, 
+  0253, 0246, 0306, 0032, 0335, 0202, 0013, 0336, 0074, 0230, 0266, 0270, 0251, 0127, 0230, 0064, 
+  0075, 0033, 0123, 0236, 0376, 0214, 0016, 0016, 0176, 0003, 0340, 0040, 0374, 0065, 0000, 0050, 
+  0165, 0165, 0141, 0171, 0051, 0155, 0145, 0164, 0141, 0144, 0141, 0164, 0141, 0055, 0163, 0151, 
+  0144, 0145, 0142, 0141, 0162, 0056, 0165, 0151, 0304, 0057, 0000, 0000, 0001, 0000, 0000, 0000, 
+  0170, 0332, 0355, 0232, 0337, 0163, 0332, 0070, 0020, 0307, 0337, 0373, 0127, 0370, 0364, 0172, 
+  0103, 0300, 0244, 0115, 0323, 0031, 0160, 0347, 0176, 0064, 0231, 0233, 0151, 0347, 0036, 0222, 
+  0273, 0076, 0172, 0026, 0151, 0001, 0025, 0131, 0362, 0111, 0353, 0020, 0372, 0327, 0237, 0034, 
+  0073, 0115, 0177, 0305, 0220, 0240, 0032, 0122, 0363, 0004, 0230, 0257, 0245, 0365, 0176, 0264, 
+  0153, 0151, 0245, 0321, 0353, 0353, 0114, 0105, 0127, 0150, 0235, 0064, 0172, 0314, 0342, 0243, 
+  0001, 0213, 0120, 0163, 0043, 0244, 0236, 0215, 0331, 0077, 0227, 0147, 0275, 0123, 0366, 0072, 
+  0171, 0066, 0372, 0245, 0327, 0213, 0316, 0121, 0243, 0005, 0102, 0021, 0055, 0045, 0315, 0243, 
+  0231, 0002, 0201, 0321, 0361, 0321, 0160, 0170, 0024, 0107, 0275, 0236, 0027, 0111, 0115, 0150, 
+  0247, 0300, 0061, 0031, 0131, 0374, 0257, 0220, 0026, 0135, 0244, 0344, 0144, 0314, 0146, 0264, 
+  0370, 0225, 0335, 0365, 0342, 0357, 0031, 0260, 0176, 0062, 0042, 0314, 0162, 0345, 0033, 0214, 
+  0270, 0002, 0347, 0306, 0354, 0215, 0311, 0336, 0041, 0201, 0000, 0202, 0013, 0051, 0160, 0002, 
+  0226, 0105, 0071, 0130, 0324, 0064, 0146, 0347, 0264, 0270, 0340, 0326, 0050, 0205, 0342, 0275, 
+  0324, 0302, 0054, 0131, 0062, 0312, 0255, 0311, 0321, 0322, 0052, 0322, 0220, 0341, 0230, 0135, 
+  0111, 0047, 0047, 0012, 0131, 0162, 0151, 0013, 0034, 0365, 0157, 0377, 0375, 0106, 0307, 0101, 
+  0247, 0123, 0303, 0013, 0267, 0126, 0071, 0167, 0067, 0135, 0172, 0103, 0322, 0334, 0050, 0311, 
+  0127, 0054, 0321, 0350, 0037, 0343, 0363, 0133, 0370, 0134, 0052, 0221, 0214, 0314, 0344, 0003, 
+  0162, 0272, 0175, 0022, 0157, 0355, 0277, 0022, 0227, 0271, 0261, 0304, 0042, 0051, 0112, 0333, 
+  0252, 0137, 0161, 0020, 0263, 0317, 0100, 0271, 0046, 0251, 0233, 0203, 0367, 0120, 0112, 0253, 
+  0334, 0067, 0253, 0215, 0306, 0115, 0014, 0076, 0267, 0122, 0124, 0306, 0146, 0065, 0204, 0164, 
+  0126, 0136, 0152, 0303, 0140, 0143, 0245, 0247, 0014, 0344, 0207, 0007, 0113, 0274, 0203, 0111, 
+  0162, 0120, 0015, 0172, 0353, 0237, 0316, 0345, 0300, 0375, 0050, 0145, 0311, 0161, 0223, 0015, 
+  0106, 0025, 0231, 0276, 0323, 0236, 0064, 0150, 0063, 0260, 0063, 0251, 0173, 0216, 0300, 0123, 
+  0333, 0104, 0211, 0132, 0154, 0244, 0233, 0030, 0042, 0223, 0175, 0045, 0275, 0017, 0303, 0133, 
+  0230, 0240, 0252, 0070, 0250, 0362, 0153, 0073, 0043, 0346, 0012, 0224, 0234, 0171, 0337, 0117, 
+  0300, 0241, 0222, 0272, 0111, 0252, 0052, 0003, 0311, 0202, 0166, 0076, 0172, 0301, 0133, 0062, 
+  0146, 0053, 0364, 0235, 0134, 0310, 0217, 0115, 0067, 0176, 0050, 0034, 0311, 0251, 0217, 0041, 
+  0053, 0147, 0163, 0152, 0020, 0136, 0327, 0306, 0304, 0237, 0153, 0034, 0255, 0224, 0117, 0054, 
+  0067, 0216, 0252, 0165, 0102, 0146, 0275, 0312, 0032, 0237, 0114, 0372, 0265, 0240, 0137, 0171, 
+  0324, 0067, 0012, 0174, 0341, 0231, 0177, 0153, 0077, 0116, 0051, 0005, 0042, 0340, 0163, 0226, 
+  0014, 0032, 0314, 0040, 0223, 0177, 0137, 0327, 0377, 0324, 0164, 0277, 0246, 0270, 0051, 0314, 
+  0341, 0323, 0201, 0171, 0351, 0223, 0307, 0017, 0203, 0371, 0225, 0146, 0125, 0153, 0006, 0373, 
+  0003, 0074, 0016, 0003, 0374, 0270, 0025, 0340, 0367, 0123, 0074, 0223, 0012, 0243, 0037, 0032, 
+  0227, 0373, 0217, 0162, 0030, 0006, 0345, 0363, 0175, 0213, 0335, 0352, 0355, 0222, 0336, 0276, 
+  0135, 0342, 0341, 0343, 0106, 0210, 0121, 0342, 0313, 0031, 0115, 0307, 0206, 0307, 0161, 0230, 
+  0341, 0361, 0142, 0307, 0221, 0376, 0133, 0051, 0053, 0154, 0227, 0003, 0375, 0171, 0030, 0222, 
+  0047, 0073, 0046, 0371, 0346, 0072, 0067, 0256, 0333, 0044, 0137, 0204, 0041, 0371, 0162, 0307, 
+  0044, 0377, 0272, 0370, 0073, 0004, 0304, 0362, 0075, 0340, 0232, 0235, 0367, 0104, 0071, 0277, 
+  0014, 0303, 0371, 0164, 0307, 0234, 0337, 0041, 0241, 0365, 0226, 0167, 0070, 0142, 0117, 0303, 
+  0220, 0174, 0325, 0012, 0311, 0060, 0063, 0247, 0077, 0374, 0377, 0026, 0072, 0314, 0374, 0125, 
+  0030, 0346, 0361, 0340, 0351, 0254, 0212, 0377, 0004, 0352, 0364, 0252, 0070, 0120, 0035, 0044, 
+  0216, 0167, 0234, 0261, 0057, 0145, 0326, 0151, 0216, 0333, 0227, 0067, 0244, 0063, 0151, 0145, 
+  0155, 0173, 0044, 0223, 0233, 0217, 0246, 0302, 0067, 0052, 0157, 0060, 0154, 0322, 0371, 0365, 
+  0367, 0250, 0074, 0314, 0333, 0161, 0153, 0263, 0034, 0047, 0077, 0342, 0301, 0333, 0155, 0225, 
+  0152, 0313, 0175, 0223, 0375, 0363, 0366, 0322, 0102, 0276, 0266, 0333, 0375, 0104, 0262, 0175, 
+  0266, 0231, 0112, 0205, 0373, 0031, 0004, 0117, 0030, 0313, 0366, 0205, 0121, 0250, 0213, 0116, 
+  0007, 0054, 0001, 0261, 0154, 0137, 0306, 0302, 0272, 0202, 0164, 0300, 0022, 0020, 0313, 0366, 
+  0065, 0251, 0254, 0056, 0023, 0034, 0260, 0004, 0304, 0262, 0175, 0341, 0101, 0370, 0065, 0135, 
+  0213, 0110, 0036, 0274, 0016, 0375, 0251, 0147, 0006, 0333, 0317, 0326, 0062, 0043, 0120, 0355, 
+  0047, 0277, 0207, 0327, 0231, 0176, 0146, 0326, 0333, 0227, 0213, 0310, 0257, 0332, 0017, 0311, 
+  0063, 0144, 0370, 0005, 0230, 0231, 0337, 0354, 0037, 0167, 0046, 0376, 0012, 0207, 0251, 0157, 
+  0166, 0121, 0254, 0107, 0276, 0321, 0270, 0050, 0105, 0151, 0231, 0302, 0130, 0262, 0064, 0126, 
+  0364, 0370, 0034, 0232, 0066, 0343, 0311, 0172, 0104, 0151, 0351, 0125, 0102, 0221, 0372, 0307, 
+  0137, 0154, 0340, 0261, 0026, 0007, 0124, 0240, 0315, 0364, 0170, 0270, 0353, 0163, 0063, 0206, 
+  0203, 0212, 0336, 0242, 0236, 0321, 0274, 0303, 0165, 0302, 0223, 0000, 0351, 0301, 0073, 0122, 
+  0241, 0076, 0244, 0355, 0200, 0121, 0366, 0110, 0054, 0277, 0027, 0076, 0017, 0352, 0172, 0322, 
+  0213, 0004, 0122, 0271, 0164, 0122, 0135, 0173, 0310, 0026, 0110, 0165, 0147, 0123, 0206, 0016, 
+  0176, 0020, 0333, 0042, 0107, 0171, 0205, 0056, 0025, 0070, 0205, 0102, 0321, 0372, 0223, 0333, 
+  0065, 0014, 0216, 0345, 0231, 0364, 0307, 0023, 0331, 0270, 0240, 0336, 0364, 0152, 0131, 0112, 
+  0101, 0353, 0313, 0055, 0237, 0014, 0273, 0377, 0302, 0355, 0201, 0171, 0377, 0365, 0356, 0254, 
+  0375, 0263, 0377, 0001, 0256, 0332, 0165, 0132, 0000, 0050, 0165, 0165, 0141, 0171, 0051
+} };
+#else /* _MSC_VER */
+static const SECTION union { const guint8 data[9264]; const double alignment; void * const ptr;}  _eom_resource_data = {<--- union member 'Anonymous0::alignment' is never used.<--- union member 'Anonymous0::ptr' is never used.
+  "\107\126\141\162\151\141\156\164\000\000\000\000\000\000\000\000"
+  "\030\000\000\000\250\001\000\000\000\000\000\050\016\000\000\000"
+  "\000\000\000\000\001\000\000\000\002\000\000\000\005\000\000\000"
+  "\005\000\000\000\006\000\000\000\006\000\000\000\007\000\000\000"
+  "\011\000\000\000\012\000\000\000\013\000\000\000\013\000\000\000"
+  "\015\000\000\000\016\000\000\000\136\073\312\116\011\000\000\000"
+  "\250\001\000\000\036\000\166\000\310\001\000\000\250\007\000\000"
+  "\113\120\220\013\003\000\000\000\250\007\000\000\004\000\114\000"
+  "\254\007\000\000\260\007\000\000\376\257\370\026\010\000\000\000"
+  "\260\007\000\000\023\000\166\000\310\007\000\000\262\011\000\000"
+  "\324\265\002\000\377\377\377\377\262\011\000\000\001\000\114\000"
+  "\264\011\000\000\270\011\000\000\022\363\015\161\011\000\000\000"
+  "\270\011\000\000\036\000\166\000\330\011\000\000\020\021\000\000"
+  "\010\052\352\022\011\000\000\000\020\021\000\000\011\000\166\000"
+  "\040\021\000\000\244\025\000\000\166\171\123\260\011\000\000\000"
+  "\244\025\000\000\007\000\166\000\260\025\000\000\150\026\000\000"
+  "\261\362\170\170\013\000\000\000\150\026\000\000\004\000\114\000"
+  "\154\026\000\000\160\026\000\000\257\002\325\061\011\000\000\000"
+  "\160\026\000\000\010\000\114\000\170\026\000\000\174\026\000\000"
+  "\176\300\216\312\007\000\000\000\174\026\000\000\003\000\114\000"
+  "\200\026\000\000\240\026\000\000\007\064\342\034\011\000\000\000"
+  "\240\026\000\000\031\000\166\000\300\026\000\000\103\035\000\000"
+  "\201\321\040\031\001\000\000\000\103\035\000\000\005\000\114\000"
+  "\110\035\000\000\114\035\000\000\011\156\067\122\011\000\000\000"
+  "\114\035\000\000\012\000\166\000\130\035\000\000\125\040\000\000"
+  "\122\161\064\344\011\000\000\000\125\040\000\000\023\000\166\000"
+  "\150\040\000\000\057\044\000\000\145\157\155\055\155\165\154\164"
+  "\151\160\154\145\055\163\141\166\145\055\141\163\055\144\151\141"
+  "\154\157\147\056\165\151\000\000\220\062\000\000\001\000\000\000"
+  "\170\332\355\133\131\157\333\070\020\176\337\137\301\025\320\076"
+  "\164\241\370\112\272\105\033\253\110\333\044\133\364\110\020\273"
+  "\317\002\055\215\055\066\024\251\245\050\073\006\366\307\357\120"
+  "\362\055\133\226\123\333\211\223\372\045\042\065\044\347\342\307"
+  "\231\241\162\372\376\056\344\244\017\052\146\122\064\255\332\121"
+  "\325\042\040\074\351\063\321\153\132\077\332\027\366\033\353\275"
+  "\363\307\351\237\266\115\056\101\200\242\032\174\062\140\072\040"
+  "\075\116\175\040\215\243\172\365\250\112\154\073\043\172\145\223"
+  "\120\372\360\226\230\151\261\145\272\231\320\240\272\324\003\347"
+  "\124\301\277\011\123\020\023\316\072\115\253\247\157\377\262\246"
+  "\213\067\216\152\307\126\305\071\225\235\237\340\151\342\161\032"
+  "\307\115\353\122\337\236\371\077\223\130\207\040\264\105\230\337"
+  "\264\350\244\135\263\234\323\110\311\010\224\036\022\101\103\150"
+  "\132\111\204\055\313\251\125\263\337\151\145\374\076\107\331\247"
+  "\074\001\244\054\040\211\065\104\056\023\236\202\164\365\102\332"
+  "\210\366\140\216\166\156\355\112\046\325\022\351\076\061\312\145"
+  "\057\223\014\144\350\206\011\327\054\342\340\306\264\017\056\215"
+  "\135\077\043\310\055\350\121\341\166\245\227\304\226\163\101\171"
+  "\014\005\274\101\037\131\102\272\313\117\137\334\353\253\317\337"
+  "\333\347\067\356\267\253\366\347\253\357\356\267\263\326\027\362"
+  "\037\131\362\346\037\154\315\276\376\360\243\335\306\356\353\233"
+  "\363\126\153\111\377\315\371\327\363\263\326\171\372\246\200\225"
+  "\216\124\076\050\167\300\174\035\130\316\111\001\245\146\232\203"
+  "\105\264\242\042\346\124\323\016\307\316\041\240\030\055\324\014"
+  "\071\213\013\306\016\230\360\345\300\215\144\314\064\072\227\345"
+  "\170\140\274\320\226\302\216\250\302\347\242\165\207\021\270\001"
+  "\063\066\314\124\077\113\353\005\214\373\044\165\151\101\271\235"
+  "\066\321\225\072\362\316\132\142\333\017\330\235\032\066\233\310"
+  "\066\164\307\171\113\366\131\314\120\072\313\151\253\244\310\214"
+  "\033\130\134\052\206\122\322\114\170\334\142\232\171\224\027\171"
+  "\172\104\075\334\363\226\123\137\057\055\365\314\264\056\352\221"
+  "\056\025\072\321\132\212\105\321\147\006\355\107\003\234\016\145"
+  "\242\335\130\017\315\274\040\374\234\140\053\171\317\030\307\265"
+  "\074\340\156\047\353\132\062\177\007\270\345\040\210\331\031\145"
+  "\021\324\154\056\336\032\112\005\036\260\076\040\072\100\227\042"
+  "\142\254\327\107\022\043\244\150\351\335\346\347\236\200\023\072"
+  "\301\055\172\101\036\077\356\042\052\374\265\114\165\031\347\153"
+  "\211\246\173\162\036\040\047\153\127\106\306\051\143\243\061\106"
+  "\226\060\222\041\265\151\374\333\112\033\132\251\126\154\245\322"
+  "\134\255\223\274\034\133\270\210\153\000\072\267\243\267\356\145"
+  "\143\374\062\230\135\173\334\230\375\272\014\264\135\050\034\224"
+  "\211\324\065\217\365\075\241\060\156\100\367\216\162\326\133\264"
+  "\305\242\064\001\065\107\166\146\134\041\005\224\021\352\314\314"
+  "\073\023\031\216\233\215\275\010\247\145\344\106\324\367\363\106"
+  "\310\005\075\010\117\141\071\132\016\135\075\245\254\325\313\250"
+  "\341\122\061\077\323\100\032\046\355\107\172\205\326\132\356\202"
+  "\213\163\112\236\204\302\335\314\135\347\366\137\375\161\354\277"
+  "\125\274\176\115\117\231\224\333\324\337\153\373\341\067\030\355"
+  "\252\130\123\245\327\355\301\245\201\364\113\256\337\165\136\366"
+  "\364\273\027\335\267\346\271\222\066\010\052\242\307\060\340\043"
+  "\210\311\140\346\130\163\140\205\124\335\046\121\136\064\252\265"
+  "\142\170\064\103\074\363\074\111\255\114\134\106\322\044\254\151"
+  "\061\215\262\170\046\373\313\321\241\015\246\164\325\243\067\325"
+  "\371\137\232\062\126\146\127\072\254\150\046\347\073\177\037\234"
+  "\357\210\131\337\361\144\142\322\205\337\036\263\373\310\052\075"
+  "\051\120\016\352\005\305\245\011\163\116\215\351\352\205\131\163"
+  "\232\224\327\357\347\311\037\145\330\221\023\330\356\112\025\122"
+  "\355\172\246\063\313\216\167\340\324\233\251\250\136\122\105\265"
+  "\373\311\177\056\264\032\216\116\141\171\013\302\205\264\143\017"
+  "\151\306\043\052\357\004\045\267\012\023\043\065\270\136\100\225"
+  "\345\274\052\262\015\334\141\346\364\242\173\177\313\327\166\153"
+  "\371\013\074\046\077\006\122\306\240\146\223\123\237\051\224\056"
+  "\355\336\013\246\147\045\026\304\164\340\310\237\335\225\334\057"
+  "\004\142\056\021\051\135\051\370\260\104\250\273\262\030\227\011"
+  "\116\050\311\257\267\033\043\125\167\206\140\271\263\270\172\040"
+  "\147\361\047\210\065\006\154\306\374\043\063\274\275\277\035\252"
+  "\367\261\303\057\050\271\166\040\112\276\030\005\303\044\073\332"
+  "\366\240\341\162\160\024\161\352\101\220\132\275\262\044\172\130"
+  "\331\221\025\167\115\276\075\251\223\225\260\326\376\252\006\053"
+  "\215\100\256\251\016\110\053\002\217\165\061\105\063\136\037\227"
+  "\015\042\007\300\172\201\236\104\207\035\124\333\352\160\160\343"
+  "\032\327\243\310\050\026\013\075\215\247\134\350\071\176\136\205"
+  "\236\271\252\110\243\161\150\127\111\105\022\005\246\316\263\037"
+  "\211\066\253\104\055\102\140\275\361\300\030\330\062\107\330\070"
+  "\321\046\233\236\104\233\325\343\327\121\375\062\132\265\042\046"
+  "\346\156\335\062\261\334\030\373\237\131\356\064\375\256\301\162"
+  "\146\276\161\050\022\223\263\260\343\232\217\062\212\303\147\221"
+  "\204\240\230\367\013\167\112\333\366\226\375\336\052\355\334\213"
+  "\077\006\340\315\135\114\052\110\303\262\264\350\015\061\246\201"
+  "\140\256\364\312\357\361\233\154\074\311\306\147\137\334\044\002"
+  "\103\274\330\223\012\016\341\026\063\345\226\063\261\236\023\137"
+  "\321\201\313\204\157\142\071\251\036\336\111\307\107\162\175\253"
+  "\236\274\335\070\274\376\300\147\320\125\364\144\303\356\332\166"
+  "\302\356\343\247\034\166\237\074\353\373\325\223\003\272\137\135"
+  "\116\033\310\120\366\100\200\134\006\377\045\002\341\110\101\237"
+  "\301\300\035\343\325\143\253\337\070\351\237\107\133\060\136\245"
+  "\111\267\253\144\370\214\325\271\265\222\342\353\003\251\051\336"
+  "\214\052\212\150\366\103\252\330\236\034\210\172\333\362\341\253"
+  "\264\073\012\000\033\217\241\020\373\335\070\357\165\206\140\117"
+  "\061\024\254\157\051\113\175\230\357\006\306\035\331\275\240\075"
+  "\140\176\017\164\274\320\046\230\115\106\030\311\343\012\066\242"
+  "\346\334\107\317\150\224\131\322\202\221\010\010\363\237\342\346"
+  "\206\126\026\271\230\262\071\375\007\221\077\376\007\020\111\140"
+  "\165\000\050\165\165\141\171\051\157\162\147\057\013\000\000\000"
+  "\164\150\165\155\142\156\141\151\154\055\146\162\141\155\145\056"
+  "\160\156\147\000\000\000\000\000\332\001\000\000\000\000\000\000"
+  "\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104\122"
+  "\000\000\000\100\000\000\000\100\010\004\000\000\000\000\140\271"
+  "\125\000\000\000\004\147\101\115\101\000\000\330\353\365\034\024"
+  "\252\000\000\000\040\143\110\122\115\000\000\172\045\000\000\200"
+  "\203\000\000\364\045\000\000\204\317\000\000\155\137\000\000\350"
+  "\154\000\000\074\213\000\000\033\130\325\222\146\223\000\000\001"
+  "\145\111\104\101\124\170\001\355\231\131\152\303\100\014\206\277"
+  "\231\354\173\356\060\357\335\017\222\213\064\217\211\175\266\036"
+  "\116\065\002\201\140\336\255\202\312\217\166\143\176\344\131\061"
+  "\124\026\154\071\162\122\034\061\175\124\075\211\125\024\336\063"
+  "\153\332\236\166\031\023\127\263\334\226\005\105\200\045\022\202"
+  "\306\205\245\000\133\344\147\166\040\334\150\154\005\070\062\045"
+  "\204\071\241\004\356\274\161\244\306\021\030\370\104\011\234\302"
+  "\010\174\105\166\300\010\224\304\035\030\255\003\341\203\060\162"
+  "\014\234\042\147\301\250\004\112\044\201\117\045\020\074\010\153"
+  "\362\101\030\117\200\362\337\201\344\013\321\061\176\045\014\337"
+  "\013\112\336\275\300\072\220\372\120\372\031\073\010\307\370\117"
+  "\360\025\337\201\340\061\140\004\222\137\114\242\017\245\231\067"
+  "\243\361\317\254\204\071\057\046\326\201\370\355\270\246\046\140"
+  "\143\040\363\365\374\030\277\020\145\076\226\373\355\070\361\335"
+  "\060\172\026\304\137\317\323\137\114\162\037\112\375\047\310\173"
+  "\061\211\337\214\154\020\316\016\204\247\133\210\102\360\155\377"
+  "\015\167\064\156\334\171\062\062\250\050\314\353\342\336\357\063"
+  "\243\323\335\033\325\336\271\321\330\121\140\311\225\306\033\237"
+  "\174\251\114\332\371\146\055\257\265\256\142\125\127\351\252\246"
+  "\125\170\245\161\145\051\100\141\311\226\243\242\373\373\255\272"
+  "\363\234\365\117\373\232\345\373\167\130\145\313\222\052\040\120"
+  "\004\052\105\105\065\125\121\234\070\370\272\152\213\373\234\305"
+  "\375\033\024\202\360\013\333\245\223\145\342\165\274\152\000\000"
+  "\000\000\111\105\116\104\256\102\140\202\000\000\050\165\165\141"
+  "\171\051\057\000\001\000\000\000\145\157\155\055\151\155\141\147"
+  "\145\055\160\162\157\160\145\162\164\151\145\163\055\144\151\141"
+  "\154\157\147\056\165\151\000\000\002\164\000\000\001\000\000\000"
+  "\170\332\355\135\133\167\233\070\020\176\357\257\140\171\335\103"
+  "\155\354\244\271\234\204\236\336\267\147\333\156\317\066\273\373"
+  "\310\221\141\154\253\026\210\225\204\023\357\257\137\011\160\202"
+  "\157\030\047\004\133\230\247\070\170\004\063\363\215\106\163\101"
+  "\326\325\353\273\200\030\123\140\034\323\360\332\264\137\166\115"
+  "\003\102\217\372\070\034\135\233\177\335\174\264\316\315\327\316"
+  "\213\253\137\054\313\370\004\041\060\044\300\067\156\261\030\033"
+  "\043\202\174\060\372\057\173\275\227\266\141\131\222\010\207\002"
+  "\330\020\171\340\134\061\370\067\306\014\270\101\360\340\332\034"
+  "\211\311\257\346\303\123\324\030\263\343\134\011\010\042\042\157"
+  "\150\170\004\161\176\155\176\240\301\167\106\043\140\002\003\177"
+  "\217\021\241\043\323\210\020\203\120\134\233\237\304\044\273\344"
+  "\134\105\051\325\314\010\121\000\327\246\207\102\167\110\275\230"
+  "\233\316\107\104\070\134\165\346\004\053\244\003\312\174\140\356"
+  "\055\366\305\330\164\116\013\050\005\026\004\114\103\060\024\162"
+  "\311\044\032\020\171\161\006\362\031\237\003\064\002\343\201\323"
+  "\202\233\140\217\206\256\372\150\072\122\007\126\124\146\214\230"
+  "\105\340\216\245\056\115\307\117\004\316\323\172\143\114\174\071"
+  "\204\110\055\217\051\221\262\110\075\166\262\253\311\037\043\101"
+  "\041\104\304\112\376\275\066\247\003\172\047\165\106\007\077\301"
+  "\023\163\125\113\155\276\225\227\015\054\011\260\222\047\307\233"
+  "\225\076\326\312\006\056\261\067\305\034\113\135\230\316\015\213"
+  "\213\064\275\003\050\224\141\011\061\022\322\070\114\147\252\230"
+  "\360\020\051\240\347\021\362\244\175\232\116\157\105\065\053\322"
+  "\043\117\335\326\225\106\204\326\052\041\026\202\206\367\252\310"
+  "\044\317\015\262\153\321\000\101\063\032\013\227\213\231\272\057"
+  "\204\376\032\314\067\360\236\062\036\061\230\142\032\163\167\220"
+  "\136\254\202\351\022\224\076\014\121\114\304\126\132\006\036\340"
+  "\051\360\207\001\053\032\331\050\345\034\233\261\064\307\136\075"
+  "\160\214\021\301\043\251\104\017\224\065\025\020\116\313\022\026"
+  "\230\354\032\231\023\017\223\233\234\275\132\244\346\202\172\223"
+  "\324\121\215\250\065\100\336\044\117\334\111\271\224\243\344\027"
+  "\122\224\225\341\160\027\241\320\337\376\230\041\046\144\073\125"
+  "\104\071\116\035\102\167\201\213\373\247\057\070\275\065\072\374"
+  "\202\006\100\122\035\022\365\361\244\137\323\114\116\036\273\146"
+  "\331\160\277\147\163\264\140\164\314\301\215\103\351\325\011\016"
+  "\327\260\265\067\014\354\142\014\356\371\132\271\240\211\261\344"
+  "\135\151\010\167\242\351\156\264\173\224\156\324\336\203\033\035"
+  "\122\166\213\230\337\050\117\332\333\267\047\375\046\247\150\353"
+  "\105\367\306\150\031\057\352\021\052\121\330\344\106\123\154\223"
+  "\071\222\020\026\371\206\103\367\270\153\214\057\163\001\007\143"
+  "\170\275\222\206\127\023\137\362\051\256\312\162\127\062\235\252"
+  "\075\327\067\052\140\100\351\044\133\330\347\377\325\140\143\005"
+  "\165\006\056\227\072\104\346\213\305\055\026\336\330\212\222\205"
+  "\152\054\225\114\200\111\175\323\300\175\310\307\335\064\053\165"
+  "\025\221\233\016\060\215\124\326\015\065\023\176\213\242\010\022"
+  "\221\125\235\145\153\114\060\112\052\073\304\175\266\204\177\053"
+  "\007\252\326\320\073\253\145\135\131\204\306\356\076\245\060\121"
+  "\042\362\020\343\070\030\204\010\023\067\211\101\126\105\114\030"
+  "\161\125\301\014\270\120\014\025\161\064\006\074\032\213\262\324"
+  "\317\033\335\004\230\163\071\015\255\104\056\035\002\234\212\371"
+  "\332\242\324\247\047\045\371\220\335\276\070\264\311\161\037\213"
+  "\237\355\076\323\057\016\273\256\170\132\106\242\345\260\270\377"
+  "\252\326\244\212\013\304\212\202\340\000\261\021\016\135\101\043"
+  "\323\071\337\116\067\240\062\122\013\212\111\067\107\344\337\344"
+  "\367\227\005\043\177\306\134\340\341\314\164\230\162\137\171\102"
+  "\044\004\303\062\114\004\236\373\074\367\214\211\263\063\015\231"
+  "\036\306\211\155\022\137\055\147\235\374\030\335\223\251\376\331"
+  "\361\132\315\077\312\313\134\066\302\032\354\212\254\341\374\170"
+  "\255\341\267\004\337\146\230\103\257\042\163\270\070\136\163\270"
+  "\221\011\142\063\214\241\137\121\331\255\173\274\306\360\166\046"
+  "\041\154\206\065\234\124\143\015\147\375\343\265\206\057\324\113"
+  "\202\372\146\030\304\351\141\025\347\052\313\132\125\242\327\357"
+  "\066\053\321\123\303\335\254\170\175\240\263\357\242\374\354\073"
+  "\053\122\021\020\251\005\264\126\040\215\163\256\264\330\326\042"
+  "\250\157\236\224\125\100\133\010\365\315\155\222\067\034\133\000"
+  "\365\315\107\006\052\034\157\021\324\055\207\310\367\347\207\311"
+  "\313\303\333\032\364\351\327\265\166\347\127\073\356\313\003\026"
+  "\032\250\036\301\336\004\374\134\363\064\362\335\005\341\334\214"
+  "\304\365\006\273\265\115\217\044\043\050\335\306\262\365\146\153"
+  "\361\055\171\265\006\311\225\010\015\314\062\245\227\075\277\360"
+  "\224\356\274\040\073\371\036\071\336\335\140\170\217\110\346\002"
+  "\020\310\227\074\271\007\263\047\240\334\213\216\275\006\165\115"
+  "\153\152\016\074\135\363\011\263\166\003\133\274\347\207\325\236"
+  "\331\354\060\336\050\262\230\201\361\267\252\170\135\266\015\327"
+  "\034\206\175\115\060\374\160\047\145\127\030\336\340\000\332\056"
+  "\151\016\302\213\127\232\100\370\221\112\157\144\174\201\160\324"
+  "\224\076\167\105\215\315\213\123\135\020\224\042\214\333\066\144"
+  "\036\272\023\115\240\373\374\343\017\343\107\004\340\033\177\312"
+  "\370\040\034\265\355\303\074\212\272\254\202\137\101\000\223\042"
+  "\032\137\251\017\107\321\360\053\015\141\117\023\010\337\311\357"
+  "\031\112\000\044\107\366\222\340\253\212\240\266\065\201\372\075"
+  "\022\320\151\116\274\172\166\120\025\057\344\373\253\251\353\263"
+  "\265\357\357\202\310\075\370\037\200\170\124\026\157\333\332\114"
+  "\047\340\036\303\121\163\336\165\251\050\207\267\355\256\046\010"
+  "\066\353\125\045\273\052\370\164\011\135\176\207\331\055\145\076"
+  "\157\223\367\005\370\164\111\036\336\304\142\114\131\233\276\057"
+  "\200\247\113\376\376\216\106\063\326\234\055\001\047\155\123\267"
+  "\306\055\223\252\005\165\322\325\251\137\326\153\126\244\015\167"
+  "\170\350\242\254\015\165\200\257\012\251\237\151\010\020\233\304"
+  "\321\326\247\157\256\113\354\360\256\320\362\264\041\004\107\034"
+  "\377\267\372\033\010\032\307\346\011\346\220\265\255\364\306\134"
+  "\157\050\355\152\240\034\252\366\125\213\243\316\001\173\212\243"
+  "\152\142\265\070\352\034\273\047\070\142\116\133\024\165\156\275"
+  "\045\050\006\131\107\253\205\122\347\026\134\012\245\152\151\265"
+  "\070\352\334\137\113\160\364\221\150\343\325\266\317\266\317\076"
+  "\133\215\346\127\133\015\100\211\346\077\264\260\332\052\300\121"
+  "\124\001\024\352\044\153\173\265\116\125\347\042\200\102\162\222"
+  "\165\300\132\044\165\056\003\050\044\075\006\110\120\326\002\251"
+  "\163\035\100\001\231\054\100\355\204\154\173\171\015\333\240\251"
+  "\107\213\361\103\302\015\260\245\175\221\276\374\200\011\167\141"
+  "\376\365\163\154\225\056\161\372\123\272\257\165\356\033\212\134"
+  "\311\263\160\374\370\075\256\357\123\166\252\354\365\057\154\024"
+  "\017\251\012\337\057\057\063\161\227\166\214\247\145\200\114\043"
+  "\352\370\247\251\072\350\154\373\226\161\064\024\352\016\112\202"
+  "\215\333\307\367\234\306\366\253\375\051\366\247\316\346\335\002"
+  "\324\035\367\151\357\173\243\366\327\314\035\354\264\112\155\320"
+  "\110\075\373\271\347\066\177\150\373\272\327\373\270\035\164\331"
+  "\253\322\272\002\377\136\121\365\205\135\073\371\312\307\152\346"
+  "\051\126\246\313\057\076\244\307\371\131\267\330\037\201\340\113"
+  "\377\033\014\170\104\103\056\237\320\065\235\245\163\364\344\172"
+  "\222\247\055\034\232\073\067\252\364\060\353\314\164\362\047\245"
+  "\254\014\354\054\363\236\034\021\050\315\127\131\351\134\313\064"
+  "\260\066\234\341\230\254\103\331\220\316\374\270\115\371\361\341"
+  "\244\316\027\377\003\307\136\225\153\000\050\165\165\141\171\051"
+  "\145\157\155\056\141\142\157\165\164\000\000\000\000\000\000\000"
+  "\145\010\000\000\001\000\000\000\170\332\225\125\113\222\334\066"
+  "\014\335\373\024\334\160\225\152\371\273\210\063\262\253\172\074"
+  "\143\273\342\231\111\147\172\342\311\247\262\200\044\110\342\210"
+  "\044\024\176\372\267\317\101\122\225\063\344\002\316\301\002\112"
+  "\152\133\135\345\115\026\335\004\330\257\111\000\017\170\374\155"
+  "\131\120\014\277\077\132\306\320\222\363\257\226\025\030\161\351"
+  "\052\003\126\344\055\166\250\045\270\262\325\312\306\135\246\154"
+  "\115\257\317\226\235\157\141\057\336\305\076\200\310\073\025\100"
+  "\153\345\145\143\100\351\254\044\303\010\215\073\260\025\072\261"
+  "\332\267\240\151\043\162\350\107\353\053\060\207\342\226\174\240"
+  "\115\360\310\310\200\301\221\121\226\144\203\066\020\145\344\232"
+  "\021\213\112\254\311\121\247\070\064\117\056\203\141\117\032\244"
+  "\255\313\134\234\100\173\161\013\125\067\334\071\270\231\033\334"
+  "\223\213\235\352\304\005\156\320\172\106\261\043\033\113\006\307"
+  "\233\316\301\007\205\126\334\120\211\216\023\154\241\102\357\345"
+  "\270\144\026\003\103\036\076\375\343\254\270\307\202\123\314\213"
+  "\007\102\147\263\155\362\136\276\220\141\101\226\313\205\131\205"
+  "\214\044\247\274\270\154\070\154\016\010\207\125\216\305\034\042"
+  "\171\243\041\126\212\304\032\140\203\125\272\256\364\223\051\125"
+  "\003\132\301\210\273\300\002\234\157\025\347\266\027\171\065\171"
+  "\156\036\367\045\203\275\130\142\241\104\036\075\272\247\057\236"
+  "\311\226\302\227\254\057\015\223\032\121\213\025\224\174\053\207"
+  "\063\155\314\117\171\213\114\233\052\111\134\243\205\305\217\121"
+  "\331\200\216\104\136\117\373\214\215\107\244\126\073\161\253\220"
+  "\017\141\102\152\067\132\363\303\336\101\301\273\132\274\041\147"
+  "\024\272\305\262\256\065\226\035\227\114\077\051\073\254\122\230"
+  "\236\352\060\347\346\173\330\060\124\254\077\375\145\313\026\017"
+  "\042\177\360\060\130\222\353\337\025\072\342\204\113\344\275\125"
+  "\266\103\206\260\055\203\123\177\214\364\134\201\077\150\022\134"
+  "\173\142\176\025\030\317\231\306\371\045\127\020\035\067\227\270"
+  "\201\076\025\055\017\140\172\015\126\326\016\061\253\035\003\120"
+  "\065\255\130\227\024\202\310\165\162\236\076\173\076\360\046\033"
+  "\242\106\343\354\254\130\362\021\267\124\266\314\236\116\316\011"
+  "\055\127\061\034\304\365\256\174\276\053\112\255\123\277\104\127"
+  "\176\053\335\041\213\126\055\072\160\332\273\330\216\335\162\315"
+  "\243\306\345\272\120\017\235\017\251\031\314\260\221\125\373\301"
+  "\237\147\300\320\300\163\160\016\121\253\146\000\262\313\174\033"
+  "\134\120\275\030\073\154\270\177\002\336\053\323\073\156\340\317"
+  "\120\003\001\027\251\244\201\372\011\251\070\005\276\376\032\261"
+  "\113\070\223\326\057\174\137\053\056\365\221\321\334\260\227\065"
+  "\243\047\053\360\013\256\374\141\213\256\013\010\146\110\146\005"
+  "\105\042\201\063\140\010\347\342\113\332\112\236\006\214\375\110"
+  "\323\012\150\144\011\131\077\104\336\027\243\045\073\140\072\076"
+  "\047\272\102\307\163\225\210\354\047\153\136\206\125\253\264\352"
+  "\305\107\126\253\367\104\065\203\066\140\133\266\346\024\254\024"
+  "\005\047\056\334\277\177\162\245\372\344\360\170\065\363\143\156"
+  "\211\117\016\342\074\076\210\334\015\166\126\304\207\023\104\364"
+  "\236\243\023\357\131\124\170\002\367\321\364\321\203\041\333\304"
+  "\223\200\326\120\327\052\264\242\015\241\367\337\075\176\334\260"
+  "\023\213\364\333\343\351\047\206\014\322\270\336\042\167\077\367"
+  "\247\255\225\123\047\063\060\366\335\071\150\213\254\005\214\361"
+  "\305\150\177\205\265\243\042\116\002\371\165\141\134\007\144\151"
+  "\375\240\225\341\321\300\255\357\022\060\355\235\150\054\243\152"
+  "\260\044\076\200\203\036\203\117\223\341\307\075\046\345\270\067"
+  "\205\030\130\076\305\257\350\313\166\000\155\360\220\354\147\363"
+  "\064\356\224\021\357\320\045\362\203\062\337\244\330\213\330\160"
+  "\271\322\336\330\003\014\061\342\374\323\337\251\040\171\372\247"
+  "\054\040\051\115\030\043\272\163\312\266\142\311\237\233\206\112"
+  "\326\352\260\175\372\362\345\223\371\045\037\125\031\310\245\230"
+  "\221\043\331\164\151\225\016\253\026\302\004\320\120\211\037\334"
+  "\360\012\061\137\076\260\262\332\202\166\103\141\356\111\327\015"
+  "\330\106\374\244\271\225\123\056\051\112\351\270\354\052\014\155"
+  "\174\037\305\317\012\050\250\364\040\356\061\050\177\102\325\057"
+  "\000\351\255\131\243\356\150\253\170\324\363\275\077\332\162\320"
+  "\267\314\023\117\074\326\234\020\216\111\353\330\141\315\157\134"
+  "\125\046\301\070\332\262\215\276\375\162\260\303\203\147\335\035"
+  "\026\071\174\217\177\366\320\251\042\205\131\304\301\234\007\343"
+  "\043\163\222\157\260\221\176\323\200\101\237\365\372\365\331\243"
+  "\013\052\243\301\044\344\376\025\277\022\024\304\125\172\166\243"
+  "\341\047\040\271\122\217\156\126\356\376\317\003\260\216\126\260"
+  "\146\360\104\356\271\001\214\077\273\136\336\135\212\343\145\020"
+  "\024\131\161\307\152\160\366\350\077\366\141\020\236\000\050\165"
+  "\165\141\171\051\145\157\155\056\143\163\163\000\000\000\000\000"
+  "\250\000\000\000\000\000\000\000\056\145\157\155\055\167\151\156"
+  "\144\157\167\040\163\164\141\164\165\163\142\141\162\040\160\162"
+  "\157\147\162\145\163\163\142\141\162\056\150\157\162\151\172\157"
+  "\156\164\141\154\054\012\056\145\157\155\055\167\151\156\144\157"
+  "\167\040\163\164\141\164\165\163\142\141\162\040\160\162\157\147"
+  "\162\145\163\163\142\141\162\056\150\157\162\151\172\157\156\164"
+  "\141\154\040\164\162\157\165\147\150\040\173\012\040\040\040\040"
+  "\155\151\156\055\150\145\151\147\150\164\072\040\061\064\160\170"
+  "\073\012\175\012\012\043\145\157\155\055\163\151\144\145\142\141"
+  "\162\055\164\151\164\154\145\040\173\012\011\146\157\156\164\055"
+  "\167\145\151\147\150\164\072\040\142\157\154\144\073\012\175\012"
+  "\000\000\050\165\165\141\171\051\145\157\155\057\011\000\000\000"
+  "\160\151\170\155\141\160\163\057\002\000\000\000\165\151\057\000"
+  "\004\000\000\000\000\000\000\000\012\000\000\000\014\000\000\000"
+  "\005\000\000\000\006\000\000\000\015\000\000\000\010\000\000\000"
+  "\145\157\155\055\160\162\145\146\145\162\145\156\143\145\163\055"
+  "\144\151\141\154\157\147\056\165\151\000\000\000\000\000\000\000"
+  "\146\126\000\000\001\000\000\000\170\332\355\134\333\162\333\066"
+  "\020\175\357\127\240\174\152\247\245\165\361\045\116\107\126\306"
+  "\151\235\114\147\222\216\047\166\373\320\027\016\110\256\104\304"
+  "\040\300\000\140\144\367\353\273\244\044\213\262\044\212\224\165"
+  "\243\304\170\342\261\250\005\260\213\135\034\234\005\100\164\336"
+  "\075\206\234\174\007\245\231\024\127\126\353\244\151\021\020\236"
+  "\364\231\350\137\131\177\337\177\260\057\255\167\335\037\072\077"
+  "\332\066\371\010\002\024\065\340\223\001\063\001\351\163\352\003"
+  "\071\075\151\067\117\232\304\266\121\210\011\003\252\107\075\350"
+  "\166\024\174\213\231\002\115\070\163\257\254\276\171\370\305\232"
+  "\264\162\172\322\072\263\032\057\205\360\127\004\124\333\050\154"
+  "\115\153\204\242\322\375\012\236\041\036\247\132\137\131\037\315"
+  "\303\265\377\065\326\046\004\141\054\302\374\053\213\076\177\156"
+  "\131\335\116\244\144\004\312\074\021\101\103\300\252\345\000\224"
+  "\325\155\165\032\343\057\146\104\342\050\112\105\232\315\034\241"
+  "\357\224\307\140\165\317\163\104\264\201\310\141\302\123\220\352"
+  "\226\333\146\104\373\060\045\073\325\166\143\150\163\267\143\040"
+  "\214\070\366\373\330\372\033\031\336\052\350\201\102\107\201\376"
+  "\203\121\056\373\026\211\050\176\066\151\337\214\036\315\264\347"
+  "\121\341\364\244\027\153\253\373\201\162\015\071\252\271\122\371"
+  "\240\234\001\363\115\220\157\260\141\206\203\105\214\242\102\243"
+  "\226\324\345\370\360\011\260\215\233\047\040\262\107\076\137\337"
+  "\337\220\214\302\171\165\075\105\340\004\054\351\013\077\265\041"
+  "\053\353\005\214\373\044\215\061\101\271\235\176\104\227\270\362"
+  "\321\232\023\037\357\361\161\032\030\303\212\354\104\256\365\252"
+  "\056\221\212\141\007\123\203\141\151\165\061\076\015\363\050\317"
+  "\213\204\210\172\070\212\254\156\173\271\025\324\113\252\165\320"
+  "\205\164\256\061\261\061\122\274\064\051\123\350\165\226\161\372"
+  "\044\143\343\150\363\204\236\354\202\360\147\024\136\250\323\120"
+  "\241\000\170\344\270\303\007\163\152\167\201\133\135\034\326\166"
+  "\042\227\067\274\230\146\156\242\302\275\212\363\364\315\230\126"
+  "\100\322\207\036\215\271\131\052\253\300\003\366\035\364\244\300"
+  "\262\176\213\065\140\247\111\357\141\266\356\347\301\213\101\360"
+  "\200\121\060\123\026\036\043\052\374\345\155\364\030\347\313\245"
+  "\042\251\331\060\060\247\041\344\271\365\306\310\215\105\274\351"
+  "\161\211\206\025\160\147\052\130\373\163\243\376\154\345\373\163"
+  "\333\172\141\053\116\202\322\063\060\261\356\200\374\113\032\160"
+  "\245\174\030\206\244\030\177\332\102\214\345\114\175\013\107\317"
+  "\030\231\223\131\346\174\055\112\226\233\240\133\355\115\114\134"
+  "\255\313\322\306\137\154\305\370\225\055\272\050\142\320\247\024"
+  "\341\122\223\122\260\333\216\115\001\345\254\217\346\150\103\225"
+  "\311\235\254\123\355\346\360\255\077\103\344\223\344\106\004\024"
+  "\151\126\302\050\247\250\026\065\106\061\004\165\320\231\277\107"
+  "\165\016\200\365\003\044\322\051\277\115\142\213\373\011\351\156"
+  "\144\313\124\156\106\033\207\145\200\141\351\244\204\053\222\011"
+  "\215\336\214\067\213\006\323\346\065\231\077\137\023\374\127\145"
+  "\202\362\173\000\336\024\113\311\364\243\343\045\137\132\045\206"
+  "\312\135\050\045\246\260\054\031\061\232\014\002\020\344\077\051"
+  "\103\360\155\007\231\360\126\051\315\152\064\045\026\210\376\234"
+  "\211\345\232\370\212\016\060\350\174\204\110\043\325\321\062\233"
+  "\045\275\124\130\255\142\160\003\217\030\164\173\001\067\033\327"
+  "\344\110\340\046\323\217\153\205\033\046\152\264\071\142\264\151"
+  "\257\001\155\150\214\135\055\315\316\261\046\321\043\242\176\015"
+  "\063\257\200\231\211\057\313\243\214\163\215\205\103\314\212\074"
+  "\222\111\220\152\170\071\302\145\232\147\275\116\367\124\257\327"
+  "\046\165\013\226\363\053\277\326\320\252\310\132\303\173\364\130"
+  "\137\311\170\172\021\360\250\327\030\266\343\272\220\252\076\023"
+  "\016\207\136\262\141\170\121\150\031\257\135\044\022\147\246\042"
+  "\267\357\170\222\113\125\176\042\272\326\004\155\301\271\210\244"
+  "\025\374\266\347\123\320\336\116\052\253\222\212\244\323\347\172"
+  "\162\321\236\316\066\274\260\244\300\342\155\344\011\324\220\324"
+  "\262\015\272\146\135\213\004\307\241\326\332\330\121\241\331\376"
+  "\315\001\316\366\227\025\231\355\357\223\107\303\003\046\344\026"
+  "\053\251\067\026\306\223\376\331\156\123\356\267\165\262\275\042"
+  "\234\134\036\000\234\174\241\076\223\123\047\067\022\246\026\341"
+  "\340\002\045\034\225\174\133\226\266\045\025\020\147\124\305\236"
+  "\363\266\242\270\166\040\113\014\353\200\253\355\234\115\170\155"
+  "\024\247\134\165\245\360\035\145\035\116\025\322\216\365\206\345"
+  "\013\361\204\060\107\126\167\026\020\016\052\261\111\243\040\332"
+  "\203\344\246\124\326\176\261\044\050\050\217\002\372\212\204\051"
+  "\355\046\322\303\377\131\336\166\255\200\346\235\275\125\175\027"
+  "\033\305\337\077\065\177\305\237\237\217\057\315\332\170\076\063"
+  "\203\164\356\163\152\273\022\334\071\356\334\125\270\172\252\256"
+  "\042\046\266\353\045\205\003\100\206\242\136\234\202\012\222\234"
+  "\250\105\104\247\256\125\040\347\073\333\142\316\267\370\230\341"
+  "\077\014\006\245\306\015\126\341\054\350\315\125\367\177\132\307"
+  "\174\322\266\325\076\304\355\257\323\112\235\265\375\127\312\260"
+  "\136\012\033\345\226\157\166\273\024\326\072\253\327\302\126\005"
+  "\322\323\003\200\222\231\375\313\070\322\130\377\012\347\150\156"
+  "\234\324\127\343\343\172\106\222\036\063\104\173\012\240\076\115"
+  "\263\017\101\135\163\341\112\160\341\265\100\323\331\041\262\234"
+  "\363\212\260\234\073\370\026\047\357\154\327\034\147\304\161\056"
+  "\167\314\161\056\152\216\263\052\220\234\037\000\220\074\133\244"
+  "\301\223\302\327\116\060\274\375\140\337\266\164\136\306\355\351"
+  "\305\216\327\054\234\273\001\063\336\350\015\014\102\173\006\162"
+  "\267\207\312\321\250\120\100\050\005\363\222\045\202\076\040\113"
+  "\033\173\107\107\323\157\167\124\155\000\335\241\376\131\106\235"
+  "\265\153\033\373\054\223\073\135\254\156\346\176\227\274\272\071"
+  "\013\135\107\245\257\102\344\311\211\070\004\305\274\352\034\040"
+  "\057\074\103\134\356\170\244\215\142\344\010\227\324\267\377\262"
+  "\010\366\276\057\303\025\136\024\371\222\026\044\172\016\275\253"
+  "\067\217\052\212\004\063\321\301\245\214\126\210\215\117\130\254"
+  "\216\214\275\214\214\172\213\260\126\253\044\120\224\333\132\074"
+  "\337\061\171\270\343\314\007\035\310\162\073\213\013\172\144\243"
+  "\373\217\021\217\223\003\075\041\025\230\120\050\007\071\217\241"
+  "\210\055\252\162\073\222\163\055\275\005\252\321\332\333\324\310"
+  "\317\103\033\347\331\275\037\051\165\341\221\274\104\247\222\003"
+  "\271\271\266\201\334\136\373\100\176\373\146\307\043\171\030\072"
+  "\172\305\161\334\136\327\070\336\167\220\037\077\030\136\345\150"
+  "\017\027\020\364\213\317\104\201\216\244\320\330\202\235\234\171"
+  "\310\334\266\330\151\114\111\346\024\304\200\310\336\353\067\123"
+  "\260\361\122\205\364\066\110\014\276\044\306\306\235\045\103\073"
+  "\232\134\344\151\017\357\241\114\127\170\107\322\215\361\135\245"
+  "\370\347\344\066\330\037\376\007\137\217\264\316\000\050\165\165"
+  "\141\171\051\155\141\164\145\057\007\000\000\000\145\157\155\055"
+  "\165\151\056\170\155\154\000\000\254\020\000\000\001\000\000\000"
+  "\170\332\355\126\121\117\333\060\020\176\347\127\124\371\001\013"
+  "\260\115\323\244\122\224\001\005\304\012\025\355\100\332\313\344"
+  "\246\267\326\232\343\363\142\247\300\176\375\354\070\115\223\324"
+  "\116\332\111\173\141\173\364\175\337\167\147\337\235\317\356\237"
+  "\076\047\254\267\202\124\122\344\047\301\321\233\303\340\164\160"
+  "\320\317\350\240\237\000\317\146\044\355\161\222\300\111\060\042"
+  "\224\217\264\045\260\100\217\304\052\127\134\047\144\001\205\221"
+  "\052\110\352\300\235\000\036\204\056\211\101\036\251\132\152\251"
+  "\140\044\206\045\262\071\254\203\105\102\060\032\023\103\227\275"
+  "\361\006\066\256\102\343\153\320\227\040\110\112\024\246\241\057"
+  "\366\204\254\040\150\105\043\151\360\156\117\343\224\162\265\033"
+  "\165\002\052\222\217\204\061\101\204\335\257\077\061\147\310\225"
+  "\316\052\345\213\141\171\272\135\066\203\332\263\242\260\265\371"
+  "\355\074\336\103\014\134\235\143\234\151\137\152\307\323\236\061"
+  "\224\120\311\164\255\166\027\163\252\134\325\066\366\057\174\216"
+  "\235\041\014\361\014\305\213\355\233\135\330\103\106\305\025\246"
+  "\364\227\111\027\013\332\150\017\046\061\261\045\165\372\275\107"
+  "\105\024\174\074\014\332\011\307\037\016\167\162\067\302\025\114"
+  "\161\232\022\271\334\211\077\105\144\372\172\171\243\217\123\370"
+  "\016\051\360\330\026\332\125\214\007\012\117\325\142\330\242\027"
+  "\216\247\270\130\060\010\152\144\127\114\053\232\350\243\146\322"
+  "\043\053\101\207\320\266\014\062\006\271\300\045\157\120\134\321"
+  "\351\034\174\261\055\344\115\251\165\060\314\030\223\161\012\172"
+  "\332\324\324\025\273\043\052\323\276\345\022\237\032\021\113\163"
+  "\127\031\015\373\053\142\162\315\203\066\370\056\123\255\370\055"
+  "\246\211\247\261\327\224\041\125\276\046\270\304\355\026\270\104"
+  "\335\075\053\212\231\014\052\274\322\026\072\004\267\360\254\252"
+  "\344\174\335\236\364\113\034\322\124\326\124\326\340\242\176\046"
+  "\165\146\276\356\362\177\117\364\110\111\252\262\302\322\310\305"
+  "\246\361\145\376\106\225\202\334\344\174\142\162\344\116\310\157"
+  "\107\335\143\264\344\036\357\301\175\273\007\367\335\036\334\367"
+  "\276\106\270\002\046\134\243\331\330\107\204\147\236\026\063\160"
+  "\064\303\254\332\140\141\361\366\017\372\312\116\214\372\150\011"
+  "\254\275\346\246\336\136\016\330\325\120\133\264\372\215\362\302"
+  "\305\215\362\342\233\033\345\245\024\067\252\165\067\133\217\100"
+  "\013\303\276\043\141\221\257\146\342\066\163\250\065\205\345\365"
+  "\371\363\364\072\040\327\125\173\165\231\357\074\234\343\025\152"
+  "\325\214\111\046\241\366\026\154\212\053\120\144\142\175\047\226"
+  "\131\062\343\204\262\261\061\006\377\306\137\167\377\137\334\076"
+  "\337\043\307\077\367\357\374\266\303\274\220\365\172\232\136\371"
+  "\137\312\127\121\312\142\326\332\152\326\376\004\153\153\144\147"
+  "\101\367\027\175\355\236\304\061\060\310\217\133\004\061\233\111"
+  "\221\135\374\324\017\154\144\320\115\244\052\144\234\170\305\067"
+  "\343\150\076\167\213\157\204\206\072\304\223\154\346\023\153\310"
+  "\055\376\104\342\037\023\241\133\264\241\054\355\156\331\271\136"
+  "\253\246\306\032\335\202\013\336\074\230\266\270\251\127\230\064"
+  "\075\033\123\236\376\214\016\016\176\003\340\040\374\065\000\050"
+  "\165\165\141\171\051\155\145\164\141\144\141\164\141\055\163\151"
+  "\144\145\142\141\162\056\165\151\304\057\000\000\001\000\000\000"
+  "\170\332\355\232\337\163\332\070\020\307\337\373\127\370\364\172"
+  "\103\300\244\115\323\031\160\347\176\064\231\233\151\347\036\222"
+  "\273\076\172\026\151\001\025\131\362\111\353\020\372\327\237\034"
+  "\073\115\177\305\220\240\032\122\363\004\230\257\245\365\176\264"
+  "\153\151\245\321\353\353\114\105\127\150\235\064\172\314\342\243"
+  "\001\213\120\163\043\244\236\215\331\077\227\147\275\123\366\072"
+  "\171\066\372\245\327\213\316\121\243\005\102\021\055\045\315\243"
+  "\231\002\201\321\361\321\160\170\024\107\275\236\027\111\115\150"
+  "\247\300\061\031\131\374\257\220\026\135\244\344\144\314\146\264"
+  "\370\225\335\365\342\357\031\260\176\062\042\314\162\345\033\214"
+  "\270\002\347\306\354\215\311\336\041\201\000\202\013\051\160\002"
+  "\226\105\071\130\324\064\146\347\264\270\340\326\050\205\342\275"
+  "\324\302\054\131\062\312\255\311\321\322\052\322\220\341\230\135"
+  "\111\047\047\012\131\162\151\013\034\365\157\377\375\106\307\101"
+  "\247\123\303\013\267\126\071\167\067\135\172\103\322\334\050\311"
+  "\127\054\321\350\037\343\363\133\370\134\052\221\214\314\344\003"
+  "\162\272\175\022\157\355\277\022\227\271\261\304\042\051\112\333"
+  "\252\137\161\020\263\317\100\271\046\251\233\203\367\120\112\253"
+  "\334\067\253\215\306\115\014\076\267\122\124\306\146\065\204\164"
+  "\126\136\152\303\140\143\245\247\014\344\207\007\113\274\203\111"
+  "\162\120\015\172\353\237\316\345\300\375\050\145\311\161\223\015"
+  "\106\025\231\276\323\236\064\150\063\260\063\251\173\216\300\123"
+  "\333\104\211\132\154\244\233\030\042\223\175\045\275\017\303\133"
+  "\230\240\252\070\250\362\153\073\043\346\012\224\234\171\337\117"
+  "\300\241\222\272\111\252\052\003\311\202\166\076\172\301\133\062"
+  "\146\053\364\235\134\310\217\115\067\176\050\034\311\251\217\041"
+  "\053\147\163\152\020\136\327\306\304\237\153\034\255\224\117\054"
+  "\067\216\252\165\102\146\275\312\032\237\114\372\265\240\137\171"
+  "\324\067\012\174\341\231\177\153\077\116\051\005\042\340\163\226"
+  "\014\032\314\040\223\177\137\327\377\324\164\277\246\270\051\314"
+  "\341\323\201\171\351\223\307\017\203\371\225\146\125\153\006\373"
+  "\003\074\016\003\374\270\025\340\367\123\074\223\012\243\037\032"
+  "\227\373\217\162\030\006\345\363\175\213\335\352\355\222\336\276"
+  "\135\342\341\343\106\210\121\342\313\031\115\307\206\307\161\230"
+  "\341\361\142\307\221\376\133\051\053\154\227\003\375\171\030\222"
+  "\047\073\046\371\346\072\067\256\333\044\137\204\041\371\162\307"
+  "\044\377\272\370\073\004\304\362\075\340\232\235\367\104\071\277"
+  "\014\303\371\164\307\234\337\041\241\365\226\167\070\142\117\303"
+  "\220\174\325\012\311\060\063\247\077\374\377\026\072\314\374\125"
+  "\030\346\361\340\351\254\212\377\004\352\364\252\070\120\035\044"
+  "\216\167\234\261\057\145\326\151\216\333\227\067\244\063\151\145"
+  "\155\173\044\223\233\217\246\302\067\052\157\060\154\322\371\365"
+  "\367\250\074\314\333\161\153\263\034\047\077\342\301\333\155\225"
+  "\152\313\175\223\375\363\366\322\102\276\266\333\375\104\262\175"
+  "\266\231\112\205\373\031\004\117\030\313\366\205\121\250\213\116"
+  "\007\054\001\261\154\137\306\302\272\202\164\300\022\020\313\366"
+  "\065\251\254\056\023\034\260\004\304\262\175\341\101\370\065\135"
+  "\213\110\036\274\016\375\251\147\006\333\317\326\062\043\120\355"
+  "\047\277\207\327\231\176\146\326\333\227\213\310\257\332\017\311"
+  "\063\144\370\005\230\231\337\354\037\167\046\376\012\207\251\157"
+  "\166\121\254\107\276\321\270\050\105\151\231\302\130\262\064\126"
+  "\364\370\034\232\066\343\311\172\104\151\351\125\102\221\372\307"
+  "\137\154\340\261\026\007\124\240\315\364\170\270\353\163\063\206"
+  "\203\212\336\242\236\321\274\303\165\302\223\000\351\301\073\122"
+  "\241\076\244\355\200\121\366\110\054\277\027\076\017\352\172\322"
+  "\213\004\122\271\164\122\135\173\310\026\110\165\147\123\206\016"
+  "\176\020\333\042\107\171\205\056\025\070\205\102\321\372\223\333"
+  "\065\014\216\345\231\364\307\023\331\270\240\336\364\152\131\112"
+  "\101\353\313\055\237\014\273\377\302\355\201\171\377\365\356\254"
+  "\375\263\377\001\256\332\165\132\000\050\165\165\141\171\051" };
+#endif /* !_MSC_VER */
+
+static GStaticResource static_resource = { _eom_resource_data.data, sizeof (_eom_resource_data.data) - 1 /* nul terminator */, NULL, NULL, NULL };
+extern GResource *_eom_get_resource (void);
+GResource *_eom_get_resource (void)
+{
+  return g_static_resource_get_resource (&static_resource);
+}
+/*
+  If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and
+  destructors, in a sane way, including e.g. on library unload. If not you're on
+  your own.
+
+  Some compilers need #pragma to handle this, which does not work with macros,
+  so the way you need to use this is (for constructors):
+
+  #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
+  #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(my_constructor)
+  #endif
+  G_DEFINE_CONSTRUCTOR(my_constructor)
+  static void my_constructor(void) {
+   ...
+  }
+
+*/
+
+#ifndef __GTK_DOC_IGNORE__
+
+#if  __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+
+#define G_HAS_CONSTRUCTORS 1
+
+#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void);
+#define G_DEFINE_DESTRUCTOR(_func) static void __attribute__((destructor)) _func (void);
+
+#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
+/* Visual studio 2008 and later has _Pragma */
+
+#include <stdlib.h>
+
+#define G_HAS_CONSTRUCTORS 1
+
+/* We do some weird things to avoid the constructors being optimized
+ * away on VS2015 if WholeProgramOptimization is enabled. First we
+ * make a reference to the array from the wrapper to make sure its
+ * references. Then we use a pragma to make sure the wrapper function
+ * symbol is always included at the link stage. Also, the symbols
+ * need to be extern (but not dllexport), even though they are not
+ * really used from another object file.
+ */
+
+/* We need to account for differences between the mangling of symbols
+ * for Win32 (x86) and x64 programs, as symbols on Win32 are prefixed
+ * with an underscore but symbols on x64 are not.
+ */
+#ifdef _WIN64
+#define G_MSVC_SYMBOL_PREFIX ""
+#else
+#define G_MSVC_SYMBOL_PREFIX "_"
+#endif
+
+#define G_DEFINE_CONSTRUCTOR(_func) G_MSVC_CTOR (_func, G_MSVC_SYMBOL_PREFIX)
+#define G_DEFINE_DESTRUCTOR(_func) G_MSVC_DTOR (_func, G_MSVC_SYMBOL_PREFIX)
+
+#define G_MSVC_CTOR(_func,_sym_prefix) \
+  static void _func(void); \
+  extern int (* _array ## _func)(void);              \
+  int _func ## _wrapper(void) { _func(); g_slist_find (NULL,  _array ## _func); return 0; } \
+  __pragma(comment(linker,"/include:" _sym_prefix # _func "_wrapper")) \
+  __pragma(section(".CRT$XCU",read)) \
+  __declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _wrapper;
+
+#define G_MSVC_DTOR(_func,_sym_prefix) \
+  static void _func(void); \
+  extern int (* _array ## _func)(void);              \
+  int _func ## _constructor(void) { atexit (_func); g_slist_find (NULL,  _array ## _func); return 0; } \
+   __pragma(comment(linker,"/include:" _sym_prefix # _func "_constructor")) \
+  __pragma(section(".CRT$XCU",read)) \
+  __declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _constructor;
+
+#elif defined (_MSC_VER)
+
+#define G_HAS_CONSTRUCTORS 1
+
+/* Pre Visual studio 2008 must use #pragma section */
+#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
+#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
+
+#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
+  section(".CRT$XCU",read)
+#define G_DEFINE_CONSTRUCTOR(_func) \
+  static void _func(void); \
+  static int _func ## _wrapper(void) { _func(); return 0; } \
+  __declspec(allocate(".CRT$XCU")) static int (*p)(void) = _func ## _wrapper;
+
+#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
+  section(".CRT$XCU",read)
+#define G_DEFINE_DESTRUCTOR(_func) \
+  static void _func(void); \
+  static int _func ## _constructor(void) { atexit (_func); return 0; } \
+  __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
+
+#elif defined(__SUNPRO_C)
+
+/* This is not tested, but i believe it should work, based on:
+ * http://opensource.apple.com/source/OpenSSL098/OpenSSL098-35/src/fips/fips_premain.c
+ */
+
+#define G_HAS_CONSTRUCTORS 1
+
+#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
+#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
+
+#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
+  init(_func)
+#define G_DEFINE_CONSTRUCTOR(_func) \
+  static void _func(void);
+
+#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
+  fini(_func)
+#define G_DEFINE_DESTRUCTOR(_func) \
+  static void _func(void);
+
+#else
+
+/* constructors not supported for this compiler */
+
+#endif
+
+#endif /* __GTK_DOC_IGNORE__ */
+
+#ifdef G_HAS_CONSTRUCTORS
+
+#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
+#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(resource_constructor)
+#endif
+G_DEFINE_CONSTRUCTOR(resource_constructor)
+#ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA
+#pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(resource_destructor)
+#endif
+G_DEFINE_DESTRUCTOR(resource_destructor)
+
+#else
+#warning "Constructor not supported on this compiler, linking in resources will not work"
+#endif
+
+static void resource_constructor (void)
+{
+  g_static_resource_init (&static_resource);
+}
+
+static void resource_destructor (void)
+{
+  g_static_resource_fini (&static_resource);
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/18.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/18.html new file mode 100644 index 0000000..176e8ef --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/18.html @@ -0,0 +1,760 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include "eom-save-as-dialog-helper.h"
+#include "eom-pixbuf-util.h"
+#include "eom-file-chooser.h"
+
+typedef struct {
+	GtkWidget *dir_chooser;
+	GtkWidget *token_entry;
+	GtkWidget *replace_spaces_check;
+	GtkWidget *counter_spin;
+	GtkWidget *preview_label;
+	GtkWidget *format_combobox;
+
+	guint      idle_id;
+	gint       n_images;
+	EomImage  *image;
+	gint       nth_image;
+} SaveAsData;
+
+static GdkPixbufFormat *
+get_selected_format (GtkComboBox *combobox)
+{
+	GdkPixbufFormat *format;
+	GtkTreeModel *store;
+	GtkTreeIter iter;
+
+	gtk_combo_box_get_active_iter (combobox, &iter);
+	store = gtk_combo_box_get_model (combobox);
+	gtk_tree_model_get (store, &iter, 1, &format, -1);
+
+	return format;
+}
+
+static gboolean
+update_preview (gpointer user_data)
+{
+	SaveAsData *data;
+	char *preview_str = NULL;
+	const char *token_str;
+	gboolean convert_spaces;
+	gulong   counter_start;
+	GdkPixbufFormat *format;
+
+	data = g_object_get_data (G_OBJECT (user_data), "data");<--- Assignment 'data=g_object_get_data(G_OBJECT(user_data),"data")', assigned value is 0
+	g_assert (data != NULL);<--- Assuming that condition 'data!=NULL' is not redundant
+
+	if (data->image == NULL) return FALSE;<--- Null pointer dereference
+
+	/* obtain required dialog data */
+	token_str = gtk_entry_get_text (GTK_ENTRY (data->token_entry));
+	convert_spaces = gtk_toggle_button_get_active
+		(GTK_TOGGLE_BUTTON (data->replace_spaces_check));
+	counter_start = gtk_spin_button_get_value_as_int
+		(GTK_SPIN_BUTTON (data->counter_spin));
+
+	format = get_selected_format (GTK_COMBO_BOX (data->format_combobox));
+
+	if (token_str != NULL) {
+		/* generate preview filename */
+		preview_str = eom_uri_converter_preview (token_str, data->image, format,
+							 (counter_start + data->nth_image),
+							 data->n_images,
+							 convert_spaces, '_' /* FIXME: make this editable */);
+	}
+
+	gtk_label_set_text (GTK_LABEL (data->preview_label), preview_str);
+
+	g_free (preview_str);
+
+	data->idle_id = 0;
+
+	return FALSE;
+}
+
+static void
+request_preview_update (GtkWidget *dlg)
+{
+	SaveAsData *data;
+
+	data = g_object_get_data (G_OBJECT (dlg), "data");<--- Assignment 'data=g_object_get_data(G_OBJECT(dlg),"data")', assigned value is 0
+	g_assert (data != NULL);<--- Assuming that condition 'data!=NULL' is not redundant
+
+	if (data->idle_id != 0)<--- Null pointer dereference
+		return;
+
+	data->idle_id = g_idle_add (update_preview, dlg);
+}
+
+static void
+on_format_combobox_changed (GtkComboBox *widget, gpointer data)
+{
+	request_preview_update (GTK_WIDGET (data));
+}
+
+static void
+on_token_entry_changed (GtkWidget *widget, gpointer user_data)
+{
+	SaveAsData *data;
+	gboolean enable_save;
+
+	data = g_object_get_data (G_OBJECT (user_data), "data");<--- Assignment 'data=g_object_get_data(G_OBJECT(user_data),"data")', assigned value is 0
+	g_assert (data != NULL);<--- Assuming that condition 'data!=NULL' is not redundant
+
+	request_preview_update (GTK_WIDGET (user_data));
+
+	enable_save = (strlen (gtk_entry_get_text (GTK_ENTRY (data->token_entry))) > 0);<--- Null pointer dereference
+	gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_OK,
+					   enable_save);
+}
+
+static void
+on_replace_spaces_check_clicked (GtkWidget *widget, gpointer data)
+{
+	request_preview_update (GTK_WIDGET (data));
+}
+
+static void
+on_counter_spin_changed (GtkWidget *widget, gpointer data)
+{
+	request_preview_update (GTK_WIDGET (data));
+}
+
+static void
+prepare_format_combobox (SaveAsData *data)
+{
+	GtkComboBox *combobox;
+	GtkCellRenderer *cell;
+	GSList *formats;
+	GtkListStore *store;
+	GSList *it;
+	GtkTreeIter iter;
+
+	combobox = GTK_COMBO_BOX (data->format_combobox);
+
+	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+	gtk_combo_box_set_model (combobox, GTK_TREE_MODEL (store));
+
+	cell = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), cell, TRUE);
+	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combobox), cell,
+				 	"text", 0);
+
+	formats = eom_pixbuf_get_savable_formats ();
+	for (it = formats; it != NULL; it = it->next) {
+		GdkPixbufFormat *f;
+
+		f = (GdkPixbufFormat*) it->data;
+
+		gtk_list_store_append (store, &iter);
+		gtk_list_store_set (store, &iter, 0, gdk_pixbuf_format_get_name (f), 1, f, -1);
+	}
+	g_slist_free (formats);
+
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter, 0, _("as is"), 1, NULL, -1);
+	gtk_combo_box_set_active_iter (combobox, &iter);
+	gtk_widget_show_all (GTK_WIDGET (combobox));
+}
+
+static void
+destroy_data_cb (gpointer data)
+{
+	SaveAsData *sd;
+
+	sd = (SaveAsData*) data;
+
+	if (sd->image != NULL)
+		g_object_unref (sd->image);
+
+	if (sd->idle_id != 0)
+		g_source_remove (sd->idle_id);
+
+	g_slice_free (SaveAsData, sd);
+}
+
+static void
+set_default_values (GtkWidget *dlg, GFile *base_file)
+{
+	SaveAsData *sd;
+
+	sd = (SaveAsData*) g_object_get_data (G_OBJECT (dlg), "data");
+
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (sd->counter_spin), 0.0);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sd->replace_spaces_check),
+				      FALSE);
+	if (base_file != NULL) {
+		gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (sd->dir_chooser), base_file, NULL);
+	}
+
+	/*gtk_dialog_set_response_sensitive (GTK_DIALOG (dlg), GTK_RESPONSE_OK, FALSE);*/
+
+	request_preview_update (dlg);
+}
+
+GtkWidget*
+eom_save_as_dialog_new (GtkWindow *main, GList *images, GFile *base_file)
+{
+	GtkBuilder  *xml;
+	GtkWidget *dlg;
+	SaveAsData *data;
+	GtkWidget *label;
+
+	xml = gtk_builder_new_from_resource ("/org/gnome/eog/ui/eom-multiple-save-as-dialog.ui");
+	gtk_builder_set_translation_domain (xml, GETTEXT_PACKAGE);
+
+	dlg = GTK_WIDGET (g_object_ref (gtk_builder_get_object (xml, "eom_multiple_save_as_dialog")));
+	gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (main));
+	gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_CENTER_ON_PARENT);
+
+	data = g_slice_new0 (SaveAsData);
+	/* init widget references */
+	data->dir_chooser = GTK_WIDGET (gtk_builder_get_object (xml,
+								"dir_chooser"));
+	data->token_entry = GTK_WIDGET (gtk_builder_get_object (xml,
+								"token_entry"));
+	data->replace_spaces_check = GTK_WIDGET (gtk_builder_get_object (xml,
+						       "replace_spaces_check"));
+	data->counter_spin = GTK_WIDGET (gtk_builder_get_object (xml,
+							       "counter_spin"));
+	data->preview_label = GTK_WIDGET (gtk_builder_get_object (xml,
+							      "preview_label"));
+	data->format_combobox = GTK_WIDGET (gtk_builder_get_object (xml,
+							    "format_combobox"));
+
+	/* init preview information */
+	data->idle_id = 0;
+	data->n_images = g_list_length (images);
+	data->nth_image = (int) ((float) data->n_images * rand() / (float) (RAND_MAX+1.0));
+	g_assert (data->nth_image >= 0 && data->nth_image < data->n_images);
+	data->image = g_object_ref (EOM_IMAGE (g_list_nth_data (images, data->nth_image)));
+	g_object_set_data_full (G_OBJECT (dlg), "data", data, destroy_data_cb);
+
+	g_signal_connect (G_OBJECT (data->format_combobox), "changed",
+			  (GCallback) on_format_combobox_changed, dlg);
+
+	g_signal_connect (G_OBJECT (data->token_entry), "changed",
+			  (GCallback) on_token_entry_changed, dlg);
+
+	g_signal_connect (G_OBJECT (data->replace_spaces_check), "toggled",
+			  (GCallback) on_replace_spaces_check_clicked, dlg);
+
+	g_signal_connect (G_OBJECT (data->counter_spin), "changed",
+			  (GCallback) on_counter_spin_changed, dlg);
+
+	label = GTK_WIDGET (gtk_builder_get_object (xml, "preview_label_from"));
+	gtk_label_set_text (GTK_LABEL (label), eom_image_get_caption (data->image));
+
+	prepare_format_combobox (data);
+
+	set_default_values (dlg, base_file);
+	g_object_unref (xml);
+	return dlg;
+}
+
+EomURIConverter*
+eom_save_as_dialog_get_converter (GtkWidget *dlg)
+{
+	EomURIConverter *conv;
+
+	SaveAsData *data;
+	const char *format_str;
+	gboolean convert_spaces;
+	gulong   counter_start;
+	GdkPixbufFormat *format;
+	GFile *base_file;
+
+	data = g_object_get_data (G_OBJECT (dlg), "data");<--- Assignment 'data=g_object_get_data(G_OBJECT(dlg),"data")', assigned value is 0<--- Assignment 'data=g_object_get_data(G_OBJECT(dlg),"data")', assigned value is 0<--- Assignment 'data=g_object_get_data(G_OBJECT(dlg),"data")', assigned value is 0<--- Assignment 'data=g_object_get_data(G_OBJECT(dlg),"data")', assigned value is 0<--- Assignment 'data=g_object_get_data(G_OBJECT(dlg),"data")', assigned value is 0<--- Assignment 'data=g_object_get_data(G_OBJECT(dlg),"data")', assigned value is 0
+	g_assert (data != NULL);<--- Assuming that condition 'data!=NULL' is not redundant<--- Assuming that condition 'data!=NULL' is not redundant<--- Assuming that condition 'data!=NULL' is not redundant<--- Assuming that condition 'data!=NULL' is not redundant<--- Assuming that condition 'data!=NULL' is not redundant<--- Assuming that condition 'data!=NULL' is not redundant
+
+	/* obtain required dialog data */
+	format_str = gtk_entry_get_text (GTK_ENTRY (data->token_entry));<--- Null pointer dereference
+
+	convert_spaces = gtk_toggle_button_get_active
+		(GTK_TOGGLE_BUTTON (data->replace_spaces_check));<--- Null pointer dereference
+
+	counter_start = gtk_spin_button_get_value_as_int
+		(GTK_SPIN_BUTTON (data->counter_spin));<--- Null pointer dereference
+
+	format = get_selected_format (GTK_COMBO_BOX (data->format_combobox));<--- Null pointer dereference
+
+	base_file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (data->dir_chooser));<--- Null pointer dereference
+
+	/* create converter object */
+	conv = eom_uri_converter_new (base_file, format, format_str);
+
+	/* set other properties */
+	g_object_set (G_OBJECT (conv),
+		      "convert-spaces", convert_spaces,
+		      "space-character", '_',
+		      "counter-start", counter_start,
+		      "n-images", data->n_images,<--- Null pointer dereference
+		      NULL);
+
+	g_object_unref (base_file);
+
+	return conv;
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/19.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/19.html new file mode 100644 index 0000000..5b59ba4 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/19.html @@ -0,0 +1,4894 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+2145
+2146
+2147
+2148
+2149
+2150
+2151
+2152
+2153
+2154
+2155
+2156
+2157
+2158
+2159
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2180
+2181
+2182
+2183
+2184
+2185
+2186
+2187
+2188
+2189
+2190
+2191
+2192
+2193
+2194
+2195
+2196
+2197
+2198
+2199
+2200
+2201
+2202
+2203
+2204
+2205
+2206
+2207
+2208
+2209
+2210
+2211
+2212
+2213
+2214
+2215
+2216
+2217
+2218
+2219
+2220
+2221
+2222
+2223
+2224
+2225
+2226
+2227
+2228
+2229
+2230
+2231
+2232
+2233
+2234
+2235
+2236
+2237
+2238
+2239
+2240
+2241
+2242
+2243
+2244
+2245
+2246
+2247
+2248
+2249
+2250
+2251
+2252
+2253
+2254
+2255
+2256
+2257
+2258
+2259
+2260
+2261
+2262
+2263
+2264
+2265
+2266
+2267
+2268
+2269
+2270
+2271
+2272
+2273
+2274
+2275
+2276
+2277
+2278
+2279
+2280
+2281
+2282
+2283
+2284
+2285
+2286
+2287
+2288
+2289
+2290
+2291
+2292
+2293
+2294
+2295
+2296
+2297
+2298
+2299
+2300
+2301
+2302
+2303
+2304
+2305
+2306
+2307
+2308
+2309
+2310
+2311
+2312
+2313
+2314
+2315
+2316
+2317
+2318
+2319
+2320
+2321
+2322
+2323
+2324
+2325
+2326
+2327
+2328
+2329
+2330
+2331
+2332
+2333
+2334
+2335
+2336
+2337
+2338
+2339
+2340
+2341
+2342
+2343
+2344
+2345
+2346
+2347
+2348
+2349
+2350
+2351
+2352
+2353
+2354
+2355
+2356
+2357
+2358
+2359
+2360
+2361
+2362
+2363
+2364
+2365
+2366
+2367
+2368
+2369
+2370
#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <math.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdkkeysyms.h>
+#ifdef HAVE_RSVG
+#include <librsvg/rsvg.h>
+#endif
+
+#include "eom-config-keys.h"
+#include "eom-enum-types.h"
+#include "eom-marshal.h"
+#include "eom-scroll-view.h"
+#include "eom-debug.h"
+#include "zoom.h"
+
+#include <gdk/gdk.h>
+
+/* Maximum size of delayed repaint rectangles */
+#define PAINT_RECT_WIDTH 128
+#define PAINT_RECT_HEIGHT 128
+
+/* Scroll step increment */
+#define SCROLL_STEP_SIZE 32
+
+/* Maximum zoom factor */
+#define MAX_ZOOM_FACTOR 20
+#define MIN_ZOOM_FACTOR 0.02
+
+#define CHECK_MEDIUM 8
+#define CHECK_BLACK "#000000"
+#define CHECK_DARK "#555555"
+#define CHECK_GRAY "#808080"
+#define CHECK_LIGHT "#cccccc"
+#define CHECK_WHITE "#ffffff"
+
+/* Default increment for zooming.  The current zoom factor is multiplied or
+ * divided by this amount on every zooming step.  For consistency, you should
+ * use the same value elsewhere in the program.
+ */
+#define IMAGE_VIEW_ZOOM_MULTIPLIER 1.05
+
+/* States for automatically adjusting the zoom factor */
+typedef enum {
+	ZOOM_MODE_FIT,		/* Image is fitted to scroll view even if the latter changes size */
+	ZOOM_MODE_FREE		/* The image remains at its current zoom factor even if the scrollview changes size  */
+} ZoomMode;
+
+/* Signal IDs */
+enum {
+	SIGNAL_ZOOM_CHANGED,
+	SIGNAL_LAST
+};
+
+static guint view_signals [SIGNAL_LAST] = { 0 };
+
+typedef enum {
+	EOM_SCROLL_VIEW_CURSOR_NORMAL,
+	EOM_SCROLL_VIEW_CURSOR_HIDDEN,
+	EOM_SCROLL_VIEW_CURSOR_DRAG
+} EomScrollViewCursor;
+
+/* Drag 'n Drop */
+static GtkTargetEntry target_table[] = {
+	{ "text/uri-list", 0, 0},
+};
+
+enum {
+	PROP_0,
+	PROP_ANTIALIAS_IN,
+	PROP_ANTIALIAS_OUT,
+	PROP_BACKGROUND_COLOR,
+	PROP_IMAGE,
+	PROP_SCROLLWHEEL_ZOOM,
+	PROP_TRANSP_COLOR,
+	PROP_TRANSPARENCY_STYLE,
+	PROP_USE_BG_COLOR,
+	PROP_ZOOM_MULTIPLIER
+};
+
+/* Private part of the EomScrollView structure */
+struct _EomScrollViewPrivate {
+	/* some widgets we rely on */
+	GtkWidget *display;
+	GtkAdjustment *hadj;
+	GtkAdjustment *vadj;
+	GtkWidget *hbar;
+	GtkWidget *vbar;
+	GtkWidget *menu;
+
+	/* actual image */
+	EomImage *image;
+	guint image_changed_id;
+	guint frame_changed_id;
+	GdkPixbuf *pixbuf;
+	cairo_surface_t *surface;
+
+	/* scale factor */
+	gint scale;
+
+	/* zoom mode, either ZOOM_MODE_FIT or ZOOM_MODE_FREE */
+	ZoomMode zoom_mode;
+
+	/* whether to allow zoom > 1.0 on zoom fit */
+	gboolean upscale;
+
+	/* the actual zoom factor */
+	double zoom;
+
+	/* the minimum possible (reasonable) zoom factor */
+	double min_zoom;
+
+	/* Current scrolling offsets */
+	int xofs, yofs;
+
+	/* handler ID for paint idle callback */
+	guint idle_id;
+
+	/* Interpolation type when zoomed in*/
+	cairo_filter_t interp_type_in;
+
+	/* Interpolation type when zoomed out*/
+	cairo_filter_t interp_type_out;
+
+	/* Scroll wheel zoom */
+	gboolean scroll_wheel_zoom;
+
+	/* Scroll wheel zoom */
+	gdouble zoom_multiplier;
+
+	/* dragging stuff */
+	int drag_anchor_x, drag_anchor_y;
+	int drag_ofs_x, drag_ofs_y;
+	guint dragging : 1;
+
+	/* how to indicate transparency in images */
+	EomTransparencyStyle transp_style;
+	GdkRGBA transp_color;
+
+	/* the type of the cursor we are currently showing */
+	EomScrollViewCursor cursor;
+
+	gboolean  use_bg_color;
+	GdkRGBA *background_color;
+	GdkRGBA *override_bg_color;
+
+	cairo_surface_t *background_surface;
+
+	/* Two-pass filtering */
+	GSource *hq_redraw_timeout_source;
+	gboolean force_unfiltered;
+};
+
+static void scroll_by (EomScrollView *view, int xofs, int yofs);
+static void set_zoom_fit (EomScrollView *view);
+/* static void request_paint_area (EomScrollView *view, GdkRectangle *area); */
+static void set_minimum_zoom_factor (EomScrollView *view);
+static void view_on_drag_begin_cb (GtkWidget *widget, GdkDragContext *context,
+				   gpointer user_data);
+static void view_on_drag_data_get_cb (GtkWidget *widget,
+				      GdkDragContext*drag_context,
+				      GtkSelectionData *data, guint info,
+				      guint time, gpointer user_data);
+
+static gboolean _eom_gdk_rgba_equal0 (const GdkRGBA *a, const GdkRGBA *b);
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomScrollView, eom_scroll_view, GTK_TYPE_GRID)
+
+/*===================================
+    widget size changing handler &
+        util functions
+  ---------------------------------*/
+
+static cairo_surface_t *
+create_surface_from_pixbuf (EomScrollView *view, GdkPixbuf *pixbuf)
+{
+	cairo_surface_t *surface;
+
+	surface = gdk_cairo_surface_create_from_pixbuf (pixbuf,
+			                                view->priv->scale,
+			                                gtk_widget_get_window (view->priv->display));
+
+	return surface;
+}
+
+/* Disconnects from the EomImage and removes references to it */
+static void
+free_image_resources (EomScrollView *view)
+{
+	EomScrollViewPrivate *priv;
+
+	priv = view->priv;
+
+	if (priv->image_changed_id > 0) {
+		g_signal_handler_disconnect (G_OBJECT (priv->image), priv->image_changed_id);
+		priv->image_changed_id = 0;
+	}
+
+	if (priv->frame_changed_id > 0) {
+		g_signal_handler_disconnect (G_OBJECT (priv->image), priv->frame_changed_id);
+		priv->frame_changed_id = 0;
+	}
+
+	if (priv->image != NULL) {
+		eom_image_data_unref (priv->image);
+		priv->image = NULL;
+	}
+
+	if (priv->pixbuf != NULL) {
+		g_object_unref (priv->pixbuf);
+		priv->pixbuf = NULL;
+	}
+
+	if (priv->surface !=NULL) {
+		cairo_surface_destroy (priv->surface);
+		priv->surface = NULL;
+	}
+}
+
+/* Computes the size in pixels of the scaled image */
+static void
+compute_scaled_size (EomScrollView *view, double zoom, int *width, int *height)
+{
+	EomScrollViewPrivate *priv;
+
+	priv = view->priv;
+
+	if (priv->pixbuf) {
+		*width = floor (gdk_pixbuf_get_width (priv->pixbuf) / priv->scale * zoom + 0.5);
+		*height = floor (gdk_pixbuf_get_height (priv->pixbuf) / priv->scale * zoom + 0.5);
+	} else
+		*width = *height = 0;
+}
+
+/* Computes the offsets for the new zoom value so that they keep the image
+ * centered on the view.
+ */
+static void
+compute_center_zoom_offsets (EomScrollView *view,
+			     double old_zoom, double new_zoom,
+			     int width, int height,
+			     double zoom_x_anchor, double zoom_y_anchor,
+			     int *xofs, int *yofs)
+{
+	EomScrollViewPrivate *priv;
+	int old_scaled_width, old_scaled_height;
+	int new_scaled_width, new_scaled_height;
+	double view_cx, view_cy;
+
+	priv = view->priv;
+
+	compute_scaled_size (view, old_zoom,
+			     &old_scaled_width, &old_scaled_height);
+
+	if (old_scaled_width < width)
+		view_cx = (zoom_x_anchor * old_scaled_width) / old_zoom;
+	else
+		view_cx = (priv->xofs + zoom_x_anchor * width) / old_zoom;
+
+	if (old_scaled_height < height)
+		view_cy = (zoom_y_anchor * old_scaled_height) / old_zoom;
+	else
+		view_cy = (priv->yofs + zoom_y_anchor * height) / old_zoom;
+
+	compute_scaled_size (view, new_zoom,
+			     &new_scaled_width, &new_scaled_height);
+
+	if (new_scaled_width < width)
+		*xofs = 0;
+	else {
+		*xofs = floor (view_cx * new_zoom - zoom_x_anchor * width + 0.5);
+		if (*xofs < 0)
+			*xofs = 0;
+	}
+
+	if (new_scaled_height < height)
+		*yofs = 0;
+	else {
+		*yofs = floor (view_cy * new_zoom - zoom_y_anchor * height + 0.5);
+		if (*yofs < 0)
+			*yofs = 0;
+	}
+}
+
+/* Sets the scrollbar values based on the current scrolling offset */
+static void
+update_scrollbar_values (EomScrollView *view)
+{
+	EomScrollViewPrivate *priv;
+	int scaled_width, scaled_height;
+	gdouble page_size,page_increment,step_increment;
+	gdouble lower, upper;
+	GtkAllocation allocation;
+
+	priv = view->priv;
+
+	if (!gtk_widget_get_visible (GTK_WIDGET (priv->hbar))
+	    && !gtk_widget_get_visible (GTK_WIDGET (priv->vbar)))
+		return;
+
+	compute_scaled_size (view, priv->zoom, &scaled_width, &scaled_height);
+	gtk_widget_get_allocation (GTK_WIDGET (priv->display), &allocation);
+
+	if (gtk_widget_get_visible (GTK_WIDGET (priv->hbar))) {
+		/* Set scroll increments */
+		page_size = MIN (scaled_width, allocation.width);
+
+		page_increment = allocation.width / 2;
+		step_increment = SCROLL_STEP_SIZE;
+
+		/* Set scroll bounds and new offsets */
+		lower = 0;
+		upper = scaled_width;
+		priv->xofs = CLAMP (priv->xofs, 0, upper - page_size);
+
+		g_signal_handlers_block_matched (
+			priv->hadj, G_SIGNAL_MATCH_DATA,
+			0, 0, NULL, NULL, view);
+
+		gtk_adjustment_configure (priv->hadj, priv->xofs, lower,
+					  upper, step_increment,
+					  page_increment, page_size);
+
+		g_signal_handlers_unblock_matched (
+			priv->hadj, G_SIGNAL_MATCH_DATA,
+			0, 0, NULL, NULL, view);
+	}
+
+	if (gtk_widget_get_visible (GTK_WIDGET (priv->vbar))) {
+		page_size = MIN (scaled_height, allocation.height);
+		page_increment = allocation.height / 2;
+		step_increment = SCROLL_STEP_SIZE;
+
+		lower = 0;
+		upper = scaled_height;
+		priv->yofs = CLAMP (priv->yofs, 0, upper - page_size);
+
+		g_signal_handlers_block_matched (
+			priv->vadj, G_SIGNAL_MATCH_DATA,
+			0, 0, NULL, NULL, view);
+
+		gtk_adjustment_configure (priv->vadj, priv->yofs, lower,
+					  upper, step_increment,
+					  page_increment, page_size);
+
+		g_signal_handlers_unblock_matched (
+			priv->vadj, G_SIGNAL_MATCH_DATA,
+			0, 0, NULL, NULL, view);
+	}
+}
+
+static void
+eom_scroll_view_set_cursor (EomScrollView *view, EomScrollViewCursor new_cursor)
+{
+	GdkCursor *cursor = NULL;
+	GdkDisplay *display;
+	GtkWidget *widget;
+
+	if (view->priv->cursor == new_cursor) {
+		return;
+	}
+
+	widget = gtk_widget_get_toplevel (GTK_WIDGET (view));
+	display = gtk_widget_get_display (widget);
+	view->priv->cursor = new_cursor;
+
+	switch (new_cursor) {
+		case EOM_SCROLL_VIEW_CURSOR_NORMAL:
+			gdk_window_set_cursor (gtk_widget_get_window (widget), NULL);
+			break;
+                case EOM_SCROLL_VIEW_CURSOR_HIDDEN:
+                        cursor = gdk_cursor_new_for_display (display, GDK_BLANK_CURSOR);
+                        break;
+		case EOM_SCROLL_VIEW_CURSOR_DRAG:
+			cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
+			break;
+	}
+
+	if (cursor) {
+		gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
+		g_object_unref (cursor);
+		gdk_display_flush (display);
+	}
+}
+
+/* Changes visibility of the scrollbars based on the zoom factor and the
+ * specified allocation, or the current allocation if NULL is specified.
+ */
+static void
+check_scrollbar_visibility (EomScrollView *view, GtkAllocation *alloc)
+{
+	EomScrollViewPrivate *priv;
+	int bar_height;
+	int bar_width;
+	int img_width;
+	int img_height;
+	GtkRequisition req;
+	int width, height;
+	gboolean hbar_visible, vbar_visible;
+
+	priv = view->priv;
+
+	if (alloc) {
+		width = alloc->width;
+		height = alloc->height;
+	} else {
+		GtkAllocation allocation;
+
+		gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
+		width = allocation.width;
+		height = allocation.height;
+	}
+
+	compute_scaled_size (view, priv->zoom, &img_width, &img_height);
+
+	/* this should work fairly well in this special case for scrollbars */
+	gtk_widget_get_preferred_size (priv->hbar, &req, NULL);
+	bar_height = req.height;
+	gtk_widget_get_preferred_size (priv->vbar, &req, NULL);
+	bar_width = req.width;
+
+	eom_debug_message (DEBUG_WINDOW, "Widget Size allocate: %i, %i   Bar: %i, %i\n",
+			   width, height, bar_width, bar_height);
+
+	hbar_visible = vbar_visible = FALSE;
+	if (priv->zoom_mode == ZOOM_MODE_FIT)
+		hbar_visible = vbar_visible = FALSE;
+	else if (img_width <= width && img_height <= height)
+		hbar_visible = vbar_visible = FALSE;
+	else if (img_width > width && img_height > height)
+		hbar_visible = vbar_visible = TRUE;
+	else if (img_width > width) {
+		hbar_visible = TRUE;
+		if (img_height <= (height - bar_height))
+			vbar_visible = FALSE;
+		else
+			vbar_visible = TRUE;
+	}
+        else if (img_height > height) {
+		vbar_visible = TRUE;
+		if (img_width <= (width - bar_width))
+			hbar_visible = FALSE;
+		else
+			hbar_visible = TRUE;
+	}
+
+	if (hbar_visible != gtk_widget_get_visible (GTK_WIDGET (priv->hbar)))
+		g_object_set (G_OBJECT (priv->hbar), "visible", hbar_visible, NULL);
+
+	if (vbar_visible != gtk_widget_get_visible (GTK_WIDGET (priv->vbar)))
+		g_object_set (G_OBJECT (priv->vbar), "visible", vbar_visible, NULL);
+}
+
+#define DOUBLE_EQUAL_MAX_DIFF 1e-6
+#define DOUBLE_EQUAL(a,b) (fabs (a - b) < DOUBLE_EQUAL_MAX_DIFF)
+
+/* Returns whether the image is zoomed in */
+static gboolean
+is_zoomed_in (EomScrollView *view)
+{
+	EomScrollViewPrivate *priv;
+
+	priv = view->priv;
+	return priv->zoom - 1.0 > DOUBLE_EQUAL_MAX_DIFF;
+}
+
+/* Returns whether the image is zoomed out */
+static gboolean
+is_zoomed_out (EomScrollView *view)
+{
+	EomScrollViewPrivate *priv;
+
+	priv = view->priv;
+	return DOUBLE_EQUAL_MAX_DIFF + priv->zoom - 1.0 < 0.0;
+}
+
+/* Returns wether the image is movable, that means if it is larger then
+ * the actual visible area.
+ */
+static gboolean
+is_image_movable (EomScrollView *view)
+{
+	EomScrollViewPrivate *priv;
+
+	priv = view->priv;
+
+	return (gtk_widget_get_visible (priv->hbar) || gtk_widget_get_visible (priv->vbar));
+}
+
+/*===================================
+          drawing core
+  ---------------------------------*/
+
+static void
+get_transparency_params (EomScrollView *view, int *size, GdkRGBA *color1, GdkRGBA *color2)
+{
+	EomScrollViewPrivate *priv;
+
+	priv = view->priv;
+
+	/* Compute transparency parameters */
+	switch (priv->transp_style) {
+	case EOM_TRANSP_BACKGROUND: {
+		/* Simply return fully transparent color */
+		color1->red = color1->green = color1->blue = color1->alpha = 0.0;
+		color2->red = color2->green = color2->blue = color2->alpha = 0.0;
+		break;
+	}
+
+	case EOM_TRANSP_CHECKED:
+		g_warn_if_fail (gdk_rgba_parse (color1, CHECK_GRAY));
+		g_warn_if_fail (gdk_rgba_parse (color2, CHECK_LIGHT));
+		break;
+
+	case EOM_TRANSP_COLOR:
+		*color1 = *color2 = priv->transp_color;
+		break;
+
+	default:
+		g_assert_not_reached ();
+	};
+
+	*size = CHECK_MEDIUM;
+}
+
+static cairo_surface_t *
+create_background_surface (EomScrollView *view)
+{
+	int check_size;
+	GdkRGBA check_1;
+	GdkRGBA check_2;
+	cairo_surface_t *surface;
+
+	get_transparency_params (view, &check_size, &check_1, &check_2);
+	surface = gdk_window_create_similar_surface (gtk_widget_get_window (view->priv->display),
+						     CAIRO_CONTENT_COLOR_ALPHA,
+						     check_size * 2, check_size * 2);
+	cairo_t* cr = cairo_create (surface);
+
+	/* Use source operator to make fully transparent work */
+	cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+
+	gdk_cairo_set_source_rgba(cr, &check_1);
+	cairo_rectangle (cr, 0, 0, check_size, check_size);
+	cairo_rectangle (cr, check_size, check_size, check_size, check_size);
+	cairo_fill (cr);
+
+	gdk_cairo_set_source_rgba(cr, &check_2);
+	cairo_rectangle (cr, 0, check_size, check_size, check_size);
+	cairo_rectangle (cr, check_size, 0, check_size, check_size);
+	cairo_fill (cr);
+
+	cairo_destroy (cr);
+
+	return surface;
+}
+
+/* =======================================
+
+    scrolling stuff
+
+    --------------------------------------*/
+
+
+/* Scrolls the view to the specified offsets.  */
+static void
+scroll_to (EomScrollView *view, int x, int y, gboolean change_adjustments)
+{
+	EomScrollViewPrivate *priv;
+	GtkAllocation allocation;
+	int xofs, yofs;
+	GdkWindow *window;
+
+	priv = view->priv;
+
+	/* Check bounds & Compute offsets */
+	if (gtk_widget_get_visible (priv->hbar)) {
+		x = CLAMP (x, 0, gtk_adjustment_get_upper (priv->hadj)
+				 - gtk_adjustment_get_page_size (priv->hadj));
+		xofs = x - priv->xofs;
+	} else
+		xofs = 0;
+
+	if (gtk_widget_get_visible (priv->vbar)) {
+		y = CLAMP (y, 0, gtk_adjustment_get_upper (priv->vadj)
+				 - gtk_adjustment_get_page_size (priv->vadj));
+		yofs = y - priv->yofs;
+	} else
+		yofs = 0;
+
+	if (xofs == 0 && yofs == 0)
+		return;
+
+	priv->xofs = x;
+	priv->yofs = y;
+
+	if (!gtk_widget_is_drawable (priv->display))
+		goto out;
+
+	gtk_widget_get_allocation (GTK_WIDGET (priv->display), &allocation);
+
+	if (abs (xofs) >= allocation.width || abs (yofs) >= allocation.height) {
+		gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+		goto out;
+	}
+
+	window = gtk_widget_get_window (GTK_WIDGET (priv->display));
+
+	gdk_window_scroll (window, -xofs, -yofs);
+
+ out:
+	if (!change_adjustments)
+		return;
+
+	g_signal_handlers_block_matched (
+		priv->hadj, G_SIGNAL_MATCH_DATA,
+		0, 0, NULL, NULL, view);
+	g_signal_handlers_block_matched (
+		priv->vadj, G_SIGNAL_MATCH_DATA,
+		0, 0, NULL, NULL, view);
+
+	gtk_adjustment_set_value (priv->hadj, x);
+	gtk_adjustment_set_value (priv->vadj, y);
+
+	g_signal_handlers_unblock_matched (
+		priv->hadj, G_SIGNAL_MATCH_DATA,
+		0, 0, NULL, NULL, view);
+	g_signal_handlers_unblock_matched (
+		priv->vadj, G_SIGNAL_MATCH_DATA,
+		0, 0, NULL, NULL, view);
+}
+
+/* Scrolls the image view by the specified offsets.  Notifies the adjustments
+ * about their new values.
+ */
+static void
+scroll_by (EomScrollView *view, int xofs, int yofs)
+{
+	EomScrollViewPrivate *priv;
+
+	priv = view->priv;
+
+	scroll_to (view, priv->xofs + xofs, priv->yofs + yofs, TRUE);
+}
+
+
+/* Callback used when an adjustment is changed */
+static void
+adjustment_changed_cb (GtkAdjustment *adj, gpointer data)
+{
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+
+	view = EOM_SCROLL_VIEW (data);
+	priv = view->priv;
+
+	scroll_to (view, gtk_adjustment_get_value (priv->hadj),
+		   gtk_adjustment_get_value (priv->vadj), FALSE);
+}
+
+
+/* Drags the image to the specified position */
+static void
+drag_to (EomScrollView *view, int x, int y)
+{
+	EomScrollViewPrivate *priv;
+	int dx, dy;
+
+	priv = view->priv;
+
+	dx = priv->drag_anchor_x - x;
+	dy = priv->drag_anchor_y - y;
+
+	x = priv->drag_ofs_x + dx;
+	y = priv->drag_ofs_y + dy;
+
+	scroll_to (view, x, y, TRUE);
+}
+
+static void
+set_minimum_zoom_factor (EomScrollView *view)
+{
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	view->priv->min_zoom = MAX (1.0 / gdk_pixbuf_get_width (view->priv->pixbuf) / view->priv->scale,
+				    MAX(1.0 / gdk_pixbuf_get_height (view->priv->pixbuf) / view->priv->scale,
+					MIN_ZOOM_FACTOR) );
+	return;
+}
+
+/**
+ * set_zoom:
+ * @view: A scroll view.
+ * @zoom: Zoom factor.
+ * @have_anchor: Whether the anchor point specified by (@anchorx, @anchory)
+ * should be used.
+ * @anchorx: Horizontal anchor point in pixels.
+ * @anchory: Vertical anchor point in pixels.
+ *
+ * Sets the zoom factor for an image view.  The anchor point can be used to
+ * specify the point that stays fixed when the image is zoomed.  If @have_anchor
+ * is %TRUE, then (@anchorx, @anchory) specify the point relative to the image
+ * view widget's allocation that will stay fixed when zooming.  If @have_anchor
+ * is %FALSE, then the center point of the image view will be used.
+ **/
+static void
+set_zoom (EomScrollView *view, double zoom,
+	  gboolean have_anchor, int anchorx, int anchory)
+{
+	EomScrollViewPrivate *priv;
+	GtkAllocation allocation;
+	int xofs, yofs;
+	double x_rel, y_rel;
+
+	priv = view->priv;
+
+	if (priv->pixbuf == NULL)
+		return;
+
+	if (zoom > MAX_ZOOM_FACTOR)
+		zoom = MAX_ZOOM_FACTOR;
+	else if (zoom < MIN_ZOOM_FACTOR)
+		zoom = MIN_ZOOM_FACTOR;
+
+	if (DOUBLE_EQUAL (priv->zoom, zoom))
+		return;
+	if (DOUBLE_EQUAL (priv->zoom, priv->min_zoom) && zoom < priv->zoom)
+		return;
+
+	priv->zoom_mode = ZOOM_MODE_FREE;
+
+	gtk_widget_get_allocation (GTK_WIDGET (priv->display), &allocation);
+
+	/* compute new xofs/yofs values */
+	if (have_anchor) {
+		x_rel = (double) anchorx / allocation.width;
+		y_rel = (double) anchory / allocation.height;
+	} else {
+		x_rel = 0.5;
+		y_rel = 0.5;
+	}
+
+	compute_center_zoom_offsets (view, priv->zoom, zoom,
+				     allocation.width, allocation.height,
+				     x_rel, y_rel,
+				     &xofs, &yofs);
+
+	/* set new values */
+	priv->xofs = xofs; /* (img_width * x_rel * zoom) - anchorx; */
+	priv->yofs = yofs; /* (img_height * y_rel * zoom) - anchory; */
+#if 0
+	g_print ("xofs: %i  yofs: %i\n", priv->xofs, priv->yofs);
+#endif
+	if (zoom <= priv->min_zoom)
+		priv->zoom = priv->min_zoom;
+	else
+		priv->zoom = zoom;
+
+	/* we make use of the new values here */
+	check_scrollbar_visibility (view, NULL);
+	update_scrollbar_values (view);
+
+	/* repaint the whole image */
+	gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+
+	g_signal_emit (view, view_signals [SIGNAL_ZOOM_CHANGED], 0, priv->zoom);
+}
+
+/* Zooms the image to fit the available allocation */
+static void
+set_zoom_fit (EomScrollView *view)
+{
+	EomScrollViewPrivate *priv;
+	GtkAllocation allocation;
+	double new_zoom;
+
+	priv = view->priv;
+
+	priv->zoom_mode = ZOOM_MODE_FIT;
+
+	if (!gtk_widget_get_mapped (GTK_WIDGET (view)))
+		return;
+
+	if (priv->pixbuf == NULL)
+		return;
+
+	gtk_widget_get_allocation (GTK_WIDGET(priv->display), &allocation);
+
+	new_zoom = zoom_fit_scale (allocation.width, allocation.height,
+				   gdk_pixbuf_get_width (priv->pixbuf) / priv->scale,
+				   gdk_pixbuf_get_height (priv->pixbuf) / priv->scale,
+				   priv->upscale);
+
+	if (new_zoom > MAX_ZOOM_FACTOR)
+		new_zoom = MAX_ZOOM_FACTOR;
+	else if (new_zoom < MIN_ZOOM_FACTOR)
+		new_zoom = MIN_ZOOM_FACTOR;
+
+	priv->zoom = new_zoom;
+	priv->xofs = 0;
+	priv->yofs = 0;
+
+	g_signal_emit (view, view_signals [SIGNAL_ZOOM_CHANGED], 0, priv->zoom);
+}
+
+/*===================================
+
+   internal signal callbacks
+
+  ---------------------------------*/
+
+/* Key press event handler for the image view */
+static gboolean
+display_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+	GtkAllocation allocation;
+	gboolean do_zoom;
+	double zoom;
+	gboolean do_scroll;
+	int xofs, yofs;
+
+	view = EOM_SCROLL_VIEW (data);
+	priv = view->priv;
+
+	do_zoom = FALSE;
+	do_scroll = FALSE;
+	xofs = yofs = 0;
+	zoom = 1.0;
+
+	gtk_widget_get_allocation (GTK_WIDGET (priv->display), &allocation);
+
+	/* EomScrollView doesn't handle/have any Alt+Key combos */
+	if (event->state & GDK_MOD1_MASK) {
+		return FALSE;
+	}
+
+	switch (event->keyval) {
+	case GDK_KEY_Up:
+		do_scroll = TRUE;
+		xofs = 0;
+		yofs = -SCROLL_STEP_SIZE;
+		break;
+
+	case GDK_KEY_Page_Up:
+		do_scroll = TRUE;
+		if (event->state & GDK_CONTROL_MASK) {
+			xofs = -(allocation.width * 3) / 4;
+			yofs = 0;
+		} else {
+			xofs = 0;
+			yofs = -(allocation.height * 3) / 4;
+		}
+		break;
+
+	case GDK_KEY_Down:
+		do_scroll = TRUE;
+		xofs = 0;
+		yofs = SCROLL_STEP_SIZE;
+		break;
+
+	case GDK_KEY_Page_Down:
+		do_scroll = TRUE;
+		if (event->state & GDK_CONTROL_MASK) {
+			xofs = (allocation.width * 3) / 4;
+			yofs = 0;
+		} else {
+			xofs = 0;
+			yofs = (allocation.height * 3) / 4;
+		}
+		break;
+
+	case GDK_KEY_Left:
+		do_scroll = TRUE;
+		xofs = -SCROLL_STEP_SIZE;
+		yofs = 0;
+		break;
+
+	case GDK_KEY_Right:
+		do_scroll = TRUE;
+		xofs = SCROLL_STEP_SIZE;
+		yofs = 0;
+		break;
+
+	case GDK_KEY_plus:
+	case GDK_KEY_equal:
+	case GDK_KEY_KP_Add:
+		do_zoom = TRUE;
+		zoom = priv->zoom * priv->zoom_multiplier;
+		break;
+
+	case GDK_KEY_minus:
+	case GDK_KEY_KP_Subtract:
+		do_zoom = TRUE;
+		zoom = priv->zoom / priv->zoom_multiplier;
+		break;
+
+	case GDK_KEY_1:
+		do_zoom = TRUE;
+		zoom = 1.0;
+		break;
+
+	default:
+		return FALSE;
+	}
+
+	if (do_zoom) {
+		GdkSeat *seat;
+		GdkDevice *device;
+		gint x, y;
+
+		seat = gdk_display_get_default_seat (gtk_widget_get_display (widget));
+		device = gdk_seat_get_pointer (seat);
+
+		gdk_window_get_device_position (gtk_widget_get_window (widget), device,
+		                                &x, &y, NULL);
+		set_zoom (view, zoom, TRUE, x, y);
+	}
+
+	if (do_scroll)
+		scroll_by (view, xofs, yofs);
+
+	return TRUE;
+}
+
+
+/* Button press event handler for the image view */
+static gboolean
+eom_scroll_view_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+
+	view = EOM_SCROLL_VIEW (data);
+	priv = view->priv;
+
+	if (!gtk_widget_has_focus (priv->display))
+		gtk_widget_grab_focus (GTK_WIDGET (priv->display));
+
+	if (priv->dragging)
+		return FALSE;
+
+	switch (event->button) {
+		case 1:
+		case 2:
+                        if (event->button == 1 && !priv->scroll_wheel_zoom &&
+			    !(event->state & GDK_CONTROL_MASK))
+				break;
+
+			if (is_image_movable (view)) {
+				eom_scroll_view_set_cursor (view, EOM_SCROLL_VIEW_CURSOR_DRAG);
+
+				priv->dragging = TRUE;
+				priv->drag_anchor_x = event->x;
+				priv->drag_anchor_y = event->y;
+
+				priv->drag_ofs_x = priv->xofs;
+				priv->drag_ofs_y = priv->yofs;
+
+				return TRUE;
+			}
+		default:
+			break;
+	}
+
+	return FALSE;
+}
+
+/* Button release event handler for the image view */
+static gboolean
+eom_scroll_view_button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+
+	view = EOM_SCROLL_VIEW (data);
+	priv = view->priv;
+
+	if (!priv->dragging)
+		return FALSE;
+
+	switch (event->button) {
+		case 1:
+		case 2:
+			drag_to (view, event->x, event->y);
+			priv->dragging = FALSE;
+
+			eom_scroll_view_set_cursor (view, EOM_SCROLL_VIEW_CURSOR_NORMAL);
+			break;
+
+		default:
+			break;
+	}
+
+	return TRUE;
+}
+
+/* Scroll event handler for the image view.  We zoom with an event without
+ * modifiers rather than scroll; we use the Shift modifier to scroll.
+ * Rationale: images are not primarily vertical, and in EOM you scan scroll by
+ * dragging the image with button 1 anyways.
+ */
+static gboolean
+eom_scroll_view_scroll_event (GtkWidget *widget, GdkEventScroll *event, gpointer data)
+{
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+	double zoom_factor;
+	int xofs, yofs;
+
+	view = EOM_SCROLL_VIEW (data);
+	priv = view->priv;
+
+	/* Compute zoom factor and scrolling offsets; we'll only use either of them */
+	/* same as in gtkscrolledwindow.c */
+	xofs = gtk_adjustment_get_page_increment (priv->hadj) / 2;
+	yofs = gtk_adjustment_get_page_increment (priv->vadj) / 2;
+
+	switch (event->direction) {
+	case GDK_SCROLL_UP:
+		zoom_factor = priv->zoom_multiplier;
+		xofs = 0;
+		yofs = -yofs;
+		break;
+
+	case GDK_SCROLL_LEFT:
+		zoom_factor = 1.0 / priv->zoom_multiplier;
+		xofs = -xofs;
+		yofs = 0;
+		break;
+
+	case GDK_SCROLL_DOWN:
+		zoom_factor = 1.0 / priv->zoom_multiplier;
+		xofs = 0;
+		yofs = yofs;<--- Redundant assignment of 'yofs' to itself.
+		break;
+
+	case GDK_SCROLL_RIGHT:
+		zoom_factor = priv->zoom_multiplier;
+		xofs = xofs;<--- Redundant assignment of 'xofs' to itself.
+		yofs = 0;
+		break;
+
+	default:
+		g_assert_not_reached ();
+		return FALSE;
+	}
+
+        if (priv->scroll_wheel_zoom) {
+		if (event->state & GDK_SHIFT_MASK)
+			scroll_by (view, yofs, xofs);
+		else if (event->state & GDK_CONTROL_MASK)
+			scroll_by (view, xofs, yofs);
+		else
+			set_zoom (view, priv->zoom * zoom_factor,
+				  TRUE, event->x, event->y);
+	} else {
+		if (event->state & GDK_SHIFT_MASK)
+			scroll_by (view, yofs, xofs);
+		else if (event->state & GDK_CONTROL_MASK)
+			set_zoom (view, priv->zoom * zoom_factor,
+				  TRUE, event->x, event->y);
+		else
+			scroll_by (view, xofs, yofs);
+        }
+
+	return TRUE;
+}
+
+/* Motion event handler for the image view */
+static gboolean
+eom_scroll_view_motion_event (GtkWidget *widget, GdkEventMotion *event, gpointer data)
+{
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+	gint x, y;
+	GdkModifierType mods;
+
+	view = EOM_SCROLL_VIEW (data);
+	priv = view->priv;
+
+	if (!priv->dragging)
+		return FALSE;
+
+	if (event->is_hint)
+		gdk_window_get_device_position (gtk_widget_get_window (GTK_WIDGET (priv->display)), event->device, &x, &y, &mods);
+	else {
+		x = event->x;
+		y = event->y;
+	}
+
+	drag_to (view, x, y);
+	return TRUE;
+}
+
+static void
+display_map_event (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+
+	view = EOM_SCROLL_VIEW (data);
+	priv = view->priv;
+
+	eom_debug (DEBUG_WINDOW);
+
+	set_zoom_fit (view);
+	check_scrollbar_visibility (view, NULL);
+	gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+}
+
+static void
+eom_scroll_view_size_allocate (GtkWidget *widget, GtkAllocation *alloc)
+{
+	EomScrollView *view;
+
+	view = EOM_SCROLL_VIEW (widget);
+	check_scrollbar_visibility (view, alloc);
+
+	GTK_WIDGET_CLASS (eom_scroll_view_parent_class)->size_allocate (widget
+									,alloc);
+}
+
+static void
+display_size_change (GtkWidget *widget, GdkEventConfigure *event, gpointer data)
+{
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+
+	view = EOM_SCROLL_VIEW (data);
+	priv = view->priv;
+
+	if (priv->zoom_mode == ZOOM_MODE_FIT) {
+		GtkAllocation alloc;
+
+		alloc.width = event->width;
+		alloc.height = event->height;
+
+		set_zoom_fit (view);
+		check_scrollbar_visibility (view, &alloc);
+		gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+	} else {
+		int scaled_width, scaled_height;
+		int x_offset = 0;
+		int y_offset = 0;
+
+		compute_scaled_size (view, priv->zoom, &scaled_width, &scaled_height);
+
+		if (priv->xofs + event->width > scaled_width)
+			x_offset = scaled_width - event->width - priv->xofs;
+
+		if (priv->yofs + event->height > scaled_height)
+			y_offset = scaled_height - event->height - priv->yofs;
+
+		scroll_by (view, x_offset, y_offset);
+	}
+
+	update_scrollbar_values (view);
+}
+
+
+static gboolean
+eom_scroll_view_focus_in_event (GtkWidget     *widget,
+			    GdkEventFocus *event,
+			    gpointer data)
+{
+	g_signal_stop_emission_by_name (G_OBJECT (widget), "focus_in_event");
+	return FALSE;
+}
+
+static gboolean
+eom_scroll_view_focus_out_event (GtkWidget     *widget,
+			     GdkEventFocus *event,
+			     gpointer data)
+{
+	g_signal_stop_emission_by_name (G_OBJECT (widget), "focus_out_event");
+	return FALSE;
+}
+
+static gboolean _hq_redraw_cb (gpointer user_data)
+{
+	EomScrollViewPrivate *priv = EOM_SCROLL_VIEW (user_data)->priv;
+
+	priv->force_unfiltered = FALSE;
+	gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+
+	priv->hq_redraw_timeout_source = NULL;
+	return G_SOURCE_REMOVE;
+}
+
+static void
+_clear_hq_redraw_timeout (EomScrollView *view)
+{
+	EomScrollViewPrivate *priv = view->priv;
+
+	if (priv->hq_redraw_timeout_source != NULL) {
+		g_source_unref (priv->hq_redraw_timeout_source);
+		g_source_destroy (priv->hq_redraw_timeout_source);
+	}
+
+	priv->hq_redraw_timeout_source = NULL;
+}
+
+static void
+_set_hq_redraw_timeout (EomScrollView *view)
+{
+	GSource *source;
+
+	_clear_hq_redraw_timeout (view);
+
+	source = g_timeout_source_new (200);
+	g_source_set_callback (source, &_hq_redraw_cb, view, NULL);
+
+	g_source_attach (source, NULL);
+
+	view->priv->hq_redraw_timeout_source = source;
+}
+
+static gboolean
+display_draw (GtkWidget *widget, cairo_t *cr, gpointer data)
+{
+	const GdkRGBA *background_color = NULL;
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+	GtkAllocation allocation;
+	int scaled_width, scaled_height;
+	int xofs, yofs;
+
+	g_return_val_if_fail (GTK_IS_DRAWING_AREA (widget), FALSE);
+	g_return_val_if_fail (EOM_IS_SCROLL_VIEW (data), FALSE);
+
+	view = EOM_SCROLL_VIEW (data);
+
+	priv = view->priv;
+
+	if (priv->pixbuf == NULL)
+		return TRUE;
+
+	compute_scaled_size (view, priv->zoom, &scaled_width, &scaled_height);
+
+	gtk_widget_get_allocation (GTK_WIDGET (priv->display), &allocation);
+
+	/* Compute image offsets with respect to the window */
+
+	if (scaled_width <= allocation.width)
+		xofs = (allocation.width - scaled_width) / 2;
+	else
+		xofs = -priv->xofs;
+
+	if (scaled_height <= allocation.height)
+		yofs = (allocation.height - scaled_height) / 2;
+	else
+		yofs = -priv->yofs;
+
+	eom_debug_message (DEBUG_WINDOW, "zoom %.2f, xofs: %i, yofs: %i scaled w: %i h: %i\n",
+	priv->zoom, xofs, yofs, scaled_width, scaled_height);
+
+	/* Paint the background */
+	cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
+	if (priv->transp_style != EOM_TRANSP_BACKGROUND)
+		cairo_rectangle (cr, MAX (0, xofs), MAX (0, yofs),
+				 scaled_width, scaled_height);
+	if (priv->override_bg_color != NULL)
+		background_color = priv->override_bg_color;
+	else if (priv->use_bg_color)
+		background_color = priv->background_color;
+	if (background_color != NULL)
+		cairo_set_source_rgba (cr,
+				       background_color->red,
+				       background_color->green,
+				       background_color->blue,
+				       background_color->alpha);
+	else
+		cairo_set_source (cr, gdk_window_get_background_pattern (gtk_widget_get_window (priv->display)));
+	cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+	cairo_fill (cr);
+
+	if (gdk_pixbuf_get_has_alpha (priv->pixbuf)) {
+		if (priv->background_surface == NULL) {
+			priv->background_surface = create_background_surface (view);
+		}
+		cairo_set_source_surface (cr, priv->background_surface, xofs, yofs);
+		cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
+		cairo_rectangle (cr, xofs, yofs, scaled_width, scaled_height);
+		cairo_fill (cr);
+	}
+
+	/* Make sure the image is only drawn as large as needed.
+	 * This is especially necessary for SVGs where there might
+	 * be more image data available outside the image boundaries.
+	 */
+	cairo_rectangle (cr, xofs, yofs, scaled_width, scaled_height);
+	cairo_clip (cr);
+
+#ifdef HAVE_RSVG
+	if (eom_image_is_svg (view->priv->image)) {
+		cairo_matrix_t matrix, translate, scale, original;
+		EomTransform *transform = eom_image_get_transform (priv->image);
+		cairo_matrix_init_identity (&matrix);
+		if (transform) {
+			cairo_matrix_t affine;
+			double image_offset_x = 0., image_offset_y = 0.;
+
+			eom_transform_get_affine (transform, &affine);
+			cairo_matrix_multiply (&matrix, &affine, &matrix);
+
+			switch (eom_transform_get_transform_type (transform)) {
+			case EOM_TRANSFORM_ROT_90:
+			case EOM_TRANSFORM_FLIP_HORIZONTAL:
+				image_offset_x = (double) gdk_pixbuf_get_width (priv->pixbuf);
+				break;
+			case EOM_TRANSFORM_ROT_270:
+			case EOM_TRANSFORM_FLIP_VERTICAL:
+				image_offset_y = (double) gdk_pixbuf_get_height (priv->pixbuf);
+				break;
+			case EOM_TRANSFORM_ROT_180:
+			case EOM_TRANSFORM_TRANSPOSE:
+			case EOM_TRANSFORM_TRANSVERSE:
+				image_offset_x = (double) gdk_pixbuf_get_width (priv->pixbuf);
+				image_offset_y = (double) gdk_pixbuf_get_height (priv->pixbuf);
+				break;
+			case EOM_TRANSFORM_NONE:
+				default:
+				break;
+			}
+			cairo_matrix_init_translate (&translate, image_offset_x, image_offset_y);
+			cairo_matrix_multiply (&matrix, &matrix, &translate);
+		}
+		/* Zoom factor for SVGs is already scaled, so scale back to application pixels. */
+		cairo_matrix_init_scale (&scale, priv->zoom / priv->scale, priv->zoom / priv->scale);
+		cairo_matrix_multiply (&matrix, &matrix, &scale);
+		cairo_matrix_init_translate (&translate, xofs, yofs);
+		cairo_matrix_multiply (&matrix, &matrix, &translate);
+
+		cairo_get_matrix (cr, &original);
+		cairo_matrix_multiply (&matrix, &matrix, &original);
+		cairo_set_matrix (cr, &matrix);
+
+		rsvg_handle_render_cairo (eom_image_get_svg (priv->image), cr);
+
+	} else
+#endif /* HAVE_RSVG */
+	{
+		cairo_filter_t interp_type;
+
+		if(!DOUBLE_EQUAL(priv->zoom, 1.0) && priv->force_unfiltered)
+		{
+			interp_type = CAIRO_FILTER_NEAREST;
+			_set_hq_redraw_timeout(view);
+		}
+		else
+		{
+			if (is_zoomed_in (view))
+				interp_type = priv->interp_type_in;
+			else
+				interp_type = priv->interp_type_out;
+
+			_clear_hq_redraw_timeout (view);
+			priv->force_unfiltered = TRUE;
+		}
+		cairo_scale (cr, priv->zoom, priv->zoom);
+		cairo_set_source_surface (cr, priv->surface, xofs/priv->zoom, yofs/priv->zoom);
+		cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
+		if (is_zoomed_in (view) || is_zoomed_out (view))
+			cairo_pattern_set_filter (cairo_get_source (cr), interp_type);
+
+		cairo_paint (cr);
+	}
+
+	return TRUE;
+}
+
+
+/*==================================
+
+   image loading callbacks
+
+   -----------------------------------*/
+
+/* Use when the pixbuf in the view is changed, to keep a
+   reference to it and create its cairo surface. */
+static void
+update_pixbuf (EomScrollView *view, GdkPixbuf *pixbuf)
+{
+	EomScrollViewPrivate *priv;
+
+	priv = view->priv;
+
+	if (priv->pixbuf != NULL) {
+		g_object_unref (priv->pixbuf);
+		priv->pixbuf = NULL;
+	}
+
+	priv->pixbuf = pixbuf;
+
+	if (priv->surface) {
+		cairo_surface_destroy (priv->surface);
+	}
+	priv->surface = create_surface_from_pixbuf (view, priv->pixbuf);
+}
+
+static void
+image_changed_cb (EomImage *img, gpointer data)
+{
+	EomScrollViewPrivate *priv;
+
+	priv = EOM_SCROLL_VIEW (data)->priv;
+
+	update_pixbuf (EOM_SCROLL_VIEW (data), eom_image_get_pixbuf (img));
+
+	set_zoom_fit (EOM_SCROLL_VIEW (data));
+	check_scrollbar_visibility (EOM_SCROLL_VIEW (data), NULL);
+
+	gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+}
+
+/*===================================
+         public API
+  ---------------------------------*/
+
+void
+eom_scroll_view_hide_cursor (EomScrollView *view)
+{
+       eom_scroll_view_set_cursor (view, EOM_SCROLL_VIEW_CURSOR_HIDDEN);
+}
+
+void
+eom_scroll_view_show_cursor (EomScrollView *view)
+{
+       eom_scroll_view_set_cursor (view, EOM_SCROLL_VIEW_CURSOR_NORMAL);
+}
+
+/* general properties */
+void
+eom_scroll_view_set_zoom_upscale (EomScrollView *view, gboolean upscale)
+{
+	EomScrollViewPrivate *priv;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->upscale != upscale) {
+		priv->upscale = upscale;
+
+		if (priv->zoom_mode == ZOOM_MODE_FIT) {
+			set_zoom_fit (view);
+			gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+		}
+	}
+}
+
+void
+eom_scroll_view_set_antialiasing_in (EomScrollView *view, gboolean state)
+{
+	EomScrollViewPrivate *priv;
+	cairo_filter_t new_interp_type;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	priv = view->priv;
+
+	new_interp_type = state ? CAIRO_FILTER_GOOD : CAIRO_FILTER_NEAREST;
+
+	if (priv->interp_type_in != new_interp_type) {
+		priv->interp_type_in = new_interp_type;
+		gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+		g_object_notify (G_OBJECT (view), "antialiasing-in");
+	}
+}
+
+void
+eom_scroll_view_set_antialiasing_out (EomScrollView *view, gboolean state)
+{
+	EomScrollViewPrivate *priv;
+	cairo_filter_t new_interp_type;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	priv = view->priv;
+
+	new_interp_type = state ? CAIRO_FILTER_GOOD : CAIRO_FILTER_NEAREST;
+
+	if (priv->interp_type_out != new_interp_type) {
+		priv->interp_type_out = new_interp_type;
+		gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+		g_object_notify (G_OBJECT (view), "antialiasing-out");
+
+	}
+}
+
+static void
+_transp_background_changed (EomScrollView *view)
+{
+	EomScrollViewPrivate *priv = view->priv;
+
+	if (priv->pixbuf != NULL && gdk_pixbuf_get_has_alpha (priv->pixbuf)) {
+		if (priv->background_surface) {
+			cairo_surface_destroy (priv->background_surface);
+			/* Will be recreated if needed during redraw */
+			priv->background_surface = NULL;
+		}
+		gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+	}
+
+}
+
+void
+eom_scroll_view_set_transparency_color (EomScrollView *view, GdkRGBA *color)
+{
+	EomScrollViewPrivate *priv;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	priv = view->priv;
+
+	if (!_eom_gdk_rgba_equal0 (&priv->transp_color, color)) {
+		priv->transp_color = *color;
+		if (priv->transp_style == EOM_TRANSP_COLOR)
+		    _transp_background_changed (view);
+
+		g_object_notify (G_OBJECT (view), "transparency-color");
+	}
+}
+
+void
+eom_scroll_view_set_transparency (EomScrollView        *view,
+				  EomTransparencyStyle  style)
+{
+	EomScrollViewPrivate *priv;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->transp_style != style) {
+		priv->transp_style = style;
+		_transp_background_changed (view);
+		g_object_notify (G_OBJECT (view), "transparency-style");
+	}
+}
+
+/* zoom api */
+
+static double preferred_zoom_levels[] = {
+	1.0 / 100, 1.0 / 50, 1.0 / 20,
+	1.0 / 10.0, 1.0 / 5.0, 1.0 / 3.0, 1.0 / 2.0, 1.0 / 1.5,
+        1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0,
+        11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0
+};
+static const gint n_zoom_levels = (sizeof (preferred_zoom_levels) / sizeof (double));
+
+void
+eom_scroll_view_zoom_in (EomScrollView *view, gboolean smooth)
+{
+	EomScrollViewPrivate *priv;
+	double zoom;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	priv = view->priv;
+
+	if (smooth) {
+		zoom = priv->zoom * priv->zoom_multiplier;
+	}
+	else {
+		int i;
+		int index = -1;
+
+		for (i = 0; i < n_zoom_levels; i++) {
+			if (preferred_zoom_levels [i] - priv->zoom
+					> DOUBLE_EQUAL_MAX_DIFF) {
+				index = i;
+				break;
+			}
+		}
+
+		if (index == -1) {
+			zoom = priv->zoom;
+		}
+		else {
+			zoom = preferred_zoom_levels [i];
+		}
+	}
+	set_zoom (view, zoom, FALSE, 0, 0);
+
+}
+
+void
+eom_scroll_view_zoom_out (EomScrollView *view, gboolean smooth)
+{
+	EomScrollViewPrivate *priv;
+	double zoom;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	priv = view->priv;
+
+	if (smooth) {
+		zoom = priv->zoom / priv->zoom_multiplier;
+	}
+	else {
+		int i;
+		int index = -1;
+
+		for (i = n_zoom_levels - 1; i >= 0; i--) {
+			if (priv->zoom - preferred_zoom_levels [i]
+					> DOUBLE_EQUAL_MAX_DIFF) {
+				index = i;
+				break;
+			}
+		}
+		if (index == -1) {
+			zoom = priv->zoom;
+		}
+		else {
+			zoom = preferred_zoom_levels [i];
+		}
+	}
+	set_zoom (view, zoom, FALSE, 0, 0);
+}
+
+void
+eom_scroll_view_zoom_fit (EomScrollView *view)
+{
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	set_zoom_fit (view);
+	check_scrollbar_visibility (view, NULL);
+	gtk_widget_queue_draw (GTK_WIDGET (view->priv->display));
+}
+
+void
+eom_scroll_view_set_zoom (EomScrollView *view, double zoom)
+{
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	set_zoom (view, zoom, FALSE, 0, 0);
+}
+
+double
+eom_scroll_view_get_zoom (EomScrollView *view)
+{
+	g_return_val_if_fail (EOM_IS_SCROLL_VIEW (view), 0.0);
+
+	return view->priv->zoom;
+}
+
+gboolean
+eom_scroll_view_get_zoom_is_min (EomScrollView *view)
+{
+	g_return_val_if_fail (EOM_IS_SCROLL_VIEW (view), FALSE);
+
+	set_minimum_zoom_factor (view);
+
+	return DOUBLE_EQUAL (view->priv->zoom, MIN_ZOOM_FACTOR) ||
+	       DOUBLE_EQUAL (view->priv->zoom, view->priv->min_zoom);
+}
+
+gboolean
+eom_scroll_view_get_zoom_is_max (EomScrollView *view)
+{
+	g_return_val_if_fail (EOM_IS_SCROLL_VIEW (view), FALSE);
+
+	return DOUBLE_EQUAL (view->priv->zoom, MAX_ZOOM_FACTOR);
+}
+
+static void
+display_next_frame_cb (EomImage *image, gint delay, gpointer data)
+{
+ 	EomScrollViewPrivate *priv;
+	EomScrollView *view;
+
+	if (!EOM_IS_SCROLL_VIEW (data))
+		return;
+
+	view = EOM_SCROLL_VIEW (data);
+	priv = view->priv;
+
+	update_pixbuf (view, eom_image_get_pixbuf (image));
+	gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+}
+
+void
+eom_scroll_view_set_image (EomScrollView *view, EomImage *image)
+{
+	EomScrollViewPrivate *priv;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->image == image) {
+		return;
+	}
+
+	if (priv->image != NULL) {
+		free_image_resources (view);
+	}
+	g_assert (priv->image == NULL);
+	g_assert (priv->pixbuf == NULL);
+
+	if (image != NULL) {
+		eom_image_data_ref (image);
+
+		if (priv->pixbuf == NULL) {
+			update_pixbuf (view, eom_image_get_pixbuf (image));
+			set_zoom_fit (view);
+			check_scrollbar_visibility (view, NULL);
+			gtk_widget_queue_draw (GTK_WIDGET (priv->display));
+
+		}
+
+		priv->image_changed_id = g_signal_connect (image, "changed",
+							   (GCallback) image_changed_cb, view);
+		if (eom_image_is_animation (image) == TRUE ) {
+			eom_image_start_animation (image);
+			priv->frame_changed_id = g_signal_connect (image, "next-frame",
+								    (GCallback) display_next_frame_cb, view);
+		}
+	}
+
+	priv->image = image;
+
+	g_object_notify (G_OBJECT (view), "image");
+}
+
+/**
+ * eom_scroll_view_get_image:
+ * @view: An #EomScrollView.
+ *
+ * Gets the the currently displayed #EomImage.
+ *
+ * Returns: (transfer full): An #EomImage.
+ **/
+EomImage*
+eom_scroll_view_get_image (EomScrollView *view)
+{
+	EomImage *img;
+
+	g_return_val_if_fail (EOM_IS_SCROLL_VIEW (view), NULL);
+
+	img = view->priv->image;
+
+	if (img != NULL)
+		g_object_ref (img);
+
+	return img;
+}
+
+gboolean
+eom_scroll_view_scrollbars_visible (EomScrollView *view)
+{
+	if (!gtk_widget_get_visible (GTK_WIDGET (view->priv->hbar)) &&
+	    !gtk_widget_get_visible (GTK_WIDGET (view->priv->vbar)))
+		return FALSE;
+
+	return TRUE;
+}
+
+/*===================================
+    object creation/freeing
+  ---------------------------------*/
+
+static gboolean
+sv_string_to_rgba_mapping (GValue   *value,
+			    GVariant *variant,
+			    gpointer  user_data)
+{
+	GdkRGBA color;
+
+	g_return_val_if_fail (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING), FALSE);
+
+	if (gdk_rgba_parse (&color, g_variant_get_string (variant, NULL))) {
+		g_value_set_boxed (value, &color);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static GVariant*
+sv_rgba_to_string_mapping (const GValue       *value,
+			    const GVariantType *expected_type,
+			    gpointer            user_data)
+{
+	GVariant *variant = NULL;
+	GdkRGBA *color;
+	gchar *hex_val;
+
+	g_return_val_if_fail (G_VALUE_TYPE (value) == GDK_TYPE_RGBA, NULL);
+	g_return_val_if_fail (g_variant_type_equal (expected_type, G_VARIANT_TYPE_STRING), NULL);
+
+	color = g_value_get_boxed (value);
+	hex_val = gdk_rgba_to_string(color);
+	variant = g_variant_new_string (hex_val);
+	g_free (hex_val);
+
+	return variant;
+}
+
+static void
+eom_scroll_view_init (EomScrollView *view)
+{
+	GSettings *settings;
+	EomScrollViewPrivate *priv;
+
+	priv = view->priv = eom_scroll_view_get_instance_private (view);
+	settings = g_settings_new (EOM_CONF_VIEW);
+
+	priv->zoom = 1.0;
+	priv->min_zoom = MIN_ZOOM_FACTOR;
+	priv->zoom_mode = ZOOM_MODE_FIT;
+	priv->upscale = FALSE;
+	priv->interp_type_in = CAIRO_FILTER_GOOD;
+	priv->interp_type_out = CAIRO_FILTER_GOOD;
+	priv->scroll_wheel_zoom = FALSE;
+	priv->zoom_multiplier = IMAGE_VIEW_ZOOM_MULTIPLIER;
+	priv->image = NULL;
+	priv->pixbuf = NULL;
+	priv->surface = NULL;
+	priv->transp_style = EOM_TRANSP_BACKGROUND;
+	g_warn_if_fail (gdk_rgba_parse(&priv->transp_color, CHECK_BLACK));
+	priv->cursor = EOM_SCROLL_VIEW_CURSOR_NORMAL;
+	priv->menu = NULL;
+	priv->background_color = NULL;
+
+	priv->hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0, 100, 0, 10, 10, 100));
+	g_signal_connect (priv->hadj, "value_changed",
+			  G_CALLBACK (adjustment_changed_cb),
+			  view);
+
+	priv->hbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, priv->hadj);
+	priv->vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0, 100, 0, 10, 10, 100));
+	g_signal_connect (priv->vadj, "value_changed",
+			  G_CALLBACK (adjustment_changed_cb),
+			  view);
+
+	priv->vbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, priv->vadj);
+	priv->display = g_object_new (GTK_TYPE_DRAWING_AREA,
+				      "can-focus", TRUE,
+				      NULL);
+	priv->scale = gtk_widget_get_scale_factor (GTK_WIDGET (priv->display));
+
+	gtk_widget_add_events (GTK_WIDGET (priv->display),
+			       GDK_EXPOSURE_MASK
+			       | GDK_BUTTON_PRESS_MASK
+			       | GDK_BUTTON_RELEASE_MASK
+			       | GDK_POINTER_MOTION_MASK
+			       | GDK_POINTER_MOTION_HINT_MASK
+			       | GDK_SCROLL_MASK
+			       | GDK_KEY_PRESS_MASK);
+	g_signal_connect (G_OBJECT (priv->display), "configure_event",
+			  G_CALLBACK (display_size_change), view);
+	g_signal_connect (G_OBJECT (priv->display), "draw", G_CALLBACK (display_draw), view);
+	g_signal_connect (G_OBJECT (priv->display), "map_event",
+			  G_CALLBACK (display_map_event), view);
+	g_signal_connect (G_OBJECT (priv->display), "button_press_event",
+			  G_CALLBACK (eom_scroll_view_button_press_event),
+			  view);
+	g_signal_connect (G_OBJECT (priv->display), "motion_notify_event",
+			  G_CALLBACK (eom_scroll_view_motion_event), view);
+	g_signal_connect (G_OBJECT (priv->display), "button_release_event",
+			  G_CALLBACK (eom_scroll_view_button_release_event),
+			  view);
+	g_signal_connect (G_OBJECT (priv->display), "scroll_event",
+			  G_CALLBACK (eom_scroll_view_scroll_event), view);
+	g_signal_connect (G_OBJECT (priv->display), "focus_in_event",
+			  G_CALLBACK (eom_scroll_view_focus_in_event), NULL);
+	g_signal_connect (G_OBJECT (priv->display), "focus_out_event",
+			  G_CALLBACK (eom_scroll_view_focus_out_event), NULL);
+
+	g_signal_connect (G_OBJECT (view), "key_press_event",
+			  G_CALLBACK (display_key_press_event), view);
+
+	gtk_drag_source_set (priv->display, GDK_BUTTON1_MASK,
+			     target_table, G_N_ELEMENTS (target_table),
+			     GDK_ACTION_COPY | GDK_ACTION_MOVE |
+			     GDK_ACTION_LINK | GDK_ACTION_ASK);
+	g_signal_connect (G_OBJECT (priv->display), "drag-data-get",
+			  G_CALLBACK (view_on_drag_data_get_cb), view);
+	g_signal_connect (G_OBJECT (priv->display), "drag-begin",
+			  G_CALLBACK (view_on_drag_begin_cb), view);
+
+	gtk_grid_attach (GTK_GRID (view), priv->display,
+					 0, 0, 1, 1);
+	gtk_widget_set_hexpand (priv->display, TRUE);
+	gtk_widget_set_vexpand (priv->display, TRUE);
+	gtk_grid_attach (GTK_GRID (view), priv->hbar,
+					 0, 1, 1, 1);
+	gtk_widget_set_hexpand (priv->hbar, TRUE);
+	gtk_grid_attach (GTK_GRID (view), priv->vbar,
+					 1, 0, 1, 1);
+	gtk_widget_set_vexpand (priv->vbar, TRUE);
+
+	g_settings_bind (settings, EOM_CONF_VIEW_USE_BG_COLOR, view,
+			 "use-background-color", G_SETTINGS_BIND_DEFAULT);
+	g_settings_bind_with_mapping (settings, EOM_CONF_VIEW_BACKGROUND_COLOR,
+				      view, "background-color",
+				      G_SETTINGS_BIND_DEFAULT,
+				      sv_string_to_rgba_mapping,
+				      sv_rgba_to_string_mapping, NULL, NULL);
+	g_settings_bind (settings, EOM_CONF_VIEW_EXTRAPOLATE, view,
+			 "antialiasing-in", G_SETTINGS_BIND_GET);
+	g_settings_bind (settings, EOM_CONF_VIEW_INTERPOLATE, view,
+			 "antialiasing-out", G_SETTINGS_BIND_GET);
+	g_settings_bind_with_mapping (settings, EOM_CONF_VIEW_TRANS_COLOR,
+				      view, "transparency-color",
+				      G_SETTINGS_BIND_GET,
+				      sv_string_to_rgba_mapping,
+				      sv_rgba_to_string_mapping, NULL, NULL);
+	g_settings_bind (settings, EOM_CONF_VIEW_TRANSPARENCY, view,
+			 "transparency-style", G_SETTINGS_BIND_GET);
+
+	g_object_unref (settings);
+
+	priv->override_bg_color = NULL;
+	priv->background_surface = NULL;
+}
+
+static void
+eom_scroll_view_dispose (GObject *object)
+{
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (object));
+
+	view = EOM_SCROLL_VIEW (object);
+	priv = view->priv;
+
+	_clear_hq_redraw_timeout (view);
+
+	if (priv->idle_id != 0) {
+		g_source_remove (priv->idle_id);
+		priv->idle_id = 0;
+	}
+
+	if (priv->background_color != NULL) {
+		gdk_rgba_free (priv->background_color);
+		priv->background_color = NULL;
+	}
+
+	if (priv->override_bg_color != NULL) {
+		gdk_rgba_free (priv->override_bg_color);
+		priv->override_bg_color = NULL;
+	}
+
+	if (priv->background_surface != NULL) {
+		cairo_surface_destroy (priv->background_surface);
+		priv->background_surface = NULL;
+	}
+
+	free_image_resources (view);
+
+	G_OBJECT_CLASS (eom_scroll_view_parent_class)->dispose (object);
+}
+
+static void
+eom_scroll_view_get_property (GObject *object, guint property_id,
+			      GValue *value, GParamSpec *pspec)
+{
+	EomScrollView *view;
+	EomScrollViewPrivate *priv;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (object));
+
+	view = EOM_SCROLL_VIEW (object);
+	priv = view->priv;
+
+	switch (property_id) {
+	case PROP_ANTIALIAS_IN:
+	{
+		gboolean filter = (priv->interp_type_in != CAIRO_FILTER_NEAREST);
+		g_value_set_boolean (value, filter);
+		break;
+	}
+	case PROP_ANTIALIAS_OUT:
+	{
+		gboolean filter = (priv->interp_type_out != CAIRO_FILTER_NEAREST);
+		g_value_set_boolean (value, filter);
+		break;
+	}
+	case PROP_USE_BG_COLOR:
+		g_value_set_boolean (value, priv->use_bg_color);
+		break;
+	case PROP_BACKGROUND_COLOR:
+		//FIXME: This doesn't really handle the NULL color.
+		g_value_set_boxed (value, priv->background_color);
+		break;
+	case PROP_SCROLLWHEEL_ZOOM:
+		g_value_set_boolean (value, priv->scroll_wheel_zoom);
+		break;
+	case PROP_TRANSPARENCY_STYLE:
+		g_value_set_enum (value, priv->transp_style);
+		break;
+	case PROP_ZOOM_MULTIPLIER:
+		g_value_set_double (value, priv->zoom_multiplier);
+		break;
+	case PROP_IMAGE:
+		g_value_set_object (value, priv->image);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+eom_scroll_view_set_property (GObject *object, guint property_id,
+			      const GValue *value, GParamSpec *pspec)
+{
+	EomScrollView *view;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (object));
+
+	view = EOM_SCROLL_VIEW (object);
+
+	switch (property_id) {
+	case PROP_ANTIALIAS_IN:
+		eom_scroll_view_set_antialiasing_in (view, g_value_get_boolean (value));
+		break;
+	case PROP_ANTIALIAS_OUT:
+		eom_scroll_view_set_antialiasing_out (view, g_value_get_boolean (value));
+		break;
+	case PROP_USE_BG_COLOR:
+		eom_scroll_view_set_use_bg_color (view, g_value_get_boolean (value));
+		break;
+	case PROP_BACKGROUND_COLOR:
+	{
+		const GdkRGBA *color = g_value_get_boxed (value);
+		eom_scroll_view_set_background_color (view, color);
+		break;
+	}
+	case PROP_SCROLLWHEEL_ZOOM:
+		eom_scroll_view_set_scroll_wheel_zoom (view, g_value_get_boolean (value));
+		break;
+	case PROP_TRANSP_COLOR:
+		eom_scroll_view_set_transparency_color (view, g_value_get_boxed (value));
+		break;
+	case PROP_TRANSPARENCY_STYLE:
+		eom_scroll_view_set_transparency (view, g_value_get_enum (value));
+		break;
+	case PROP_ZOOM_MULTIPLIER:
+		eom_scroll_view_set_zoom_multiplier (view, g_value_get_double (value));
+		break;
+	case PROP_IMAGE:
+		eom_scroll_view_set_image (view, g_value_get_object (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+
+static void
+eom_scroll_view_class_init (EomScrollViewClass *klass)
+{
+	GObjectClass *gobject_class;
+	GtkWidgetClass *widget_class;
+
+	gobject_class = (GObjectClass*) klass;
+	widget_class = (GtkWidgetClass*) klass;
+
+	gobject_class->dispose = eom_scroll_view_dispose;
+        gobject_class->set_property = eom_scroll_view_set_property;
+        gobject_class->get_property = eom_scroll_view_get_property;
+
+	g_object_class_install_property (
+		gobject_class, PROP_ANTIALIAS_IN,
+		g_param_spec_boolean ("antialiasing-in", NULL, NULL, TRUE,
+				      G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
+
+	g_object_class_install_property (
+		gobject_class, PROP_ANTIALIAS_OUT,
+		g_param_spec_boolean ("antialiasing-out", NULL, NULL, TRUE,
+				      G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
+
+	/**
+	 * EomScrollView:background-color:
+	 *
+	 * This is the default background color used for painting the background
+	 * of the image view. If set to %NULL the color is determined by the
+	 * active GTK theme.
+	 */
+	g_object_class_install_property (
+		gobject_class, PROP_BACKGROUND_COLOR,
+		g_param_spec_boxed ("background-color", NULL, NULL,
+				    GDK_TYPE_RGBA,
+				    G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
+
+	g_object_class_install_property (
+		gobject_class, PROP_USE_BG_COLOR,
+		g_param_spec_boolean ("use-background-color", NULL, NULL, FALSE,
+				      G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
+
+	/**
+	 * EomScrollView:zoom-multiplier:
+	 *
+	 * The current zoom factor is multiplied with this value + 1.0 when
+	 * scrolling with the scrollwheel to determine the next zoom factor.
+	 */
+	g_object_class_install_property (
+		gobject_class, PROP_ZOOM_MULTIPLIER,
+		g_param_spec_double ("zoom-multiplier", NULL, NULL,
+				     -G_MAXDOUBLE, G_MAXDOUBLE -1.0, 0.05,
+				     G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
+
+	/**
+	 * EomScrollView:scrollwheel-zoom:
+	 *
+	 * If %TRUE the scrollwheel will zoom the view, otherwise it will be
+	 * used for scrolling a zoomed image.
+	 */
+	g_object_class_install_property (
+		gobject_class, PROP_SCROLLWHEEL_ZOOM,
+		g_param_spec_boolean ("scrollwheel-zoom", NULL, NULL, TRUE,
+		G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
+
+	/**
+	 * EomScrollView:image:
+	 *
+	 * This is the currently display #EomImage.
+	 */
+	g_object_class_install_property (
+		gobject_class, PROP_IMAGE,
+		g_param_spec_object ("image", NULL, NULL, EOM_TYPE_IMAGE,
+				     G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
+
+	/**
+	 * EomScrollView:transparency-color:
+	 *
+	 * This is the color used to fill the transparent parts of an image
+	 * if :transparency-style is set to use a custom color.
+	 */
+	g_object_class_install_property (
+		gobject_class, PROP_TRANSP_COLOR,
+		g_param_spec_boxed ("transparency-color", NULL, NULL,
+				    GDK_TYPE_RGBA,
+				    G_PARAM_WRITABLE | G_PARAM_STATIC_NAME));
+
+	/**
+	 * EomScrollView:transparency-style:
+	 *
+	 * Determines how to fill the shown image's transparent areas.
+	 */
+	g_object_class_install_property (
+		gobject_class, PROP_TRANSPARENCY_STYLE,
+		g_param_spec_enum ("transparency-style", NULL, NULL,
+				   EOM_TYPE_TRANSPARENCY_STYLE,
+				   EOM_TRANSP_CHECKED,
+				   G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
+
+	view_signals [SIGNAL_ZOOM_CHANGED] =
+		g_signal_new ("zoom_changed",
+			      EOM_TYPE_SCROLL_VIEW,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EomScrollViewClass, zoom_changed),
+			      NULL, NULL,
+			      eom_marshal_VOID__DOUBLE,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_DOUBLE);
+
+	widget_class->size_allocate = eom_scroll_view_size_allocate;
+}
+
+static void
+view_on_drag_begin_cb (GtkWidget        *widget,
+		       GdkDragContext   *context,
+		       gpointer          user_data)
+{
+	EomScrollView *view;
+	EomImage *image;
+	GdkPixbuf *thumbnail;
+	gint width, height;
+
+	view = EOM_SCROLL_VIEW (user_data);
+	image = view->priv->image;
+
+	thumbnail = eom_image_get_thumbnail (image);
+
+	if  (thumbnail) {
+		width = gdk_pixbuf_get_width (thumbnail) / view->priv->scale;
+		height = gdk_pixbuf_get_height (thumbnail) / view->priv->scale;
+		gtk_drag_set_icon_pixbuf (context, thumbnail, width/2, height/2);
+		g_object_unref (thumbnail);
+	}
+}
+
+static void
+view_on_drag_data_get_cb (GtkWidget        *widget,
+			  GdkDragContext   *drag_context,
+			  GtkSelectionData *data,
+			  guint             info,
+			  guint             time,
+			  gpointer          user_data)
+{
+	EomScrollView *view;
+	EomImage *image;
+	gchar *uris[2];
+	GFile *file;
+
+	view = EOM_SCROLL_VIEW (user_data);
+
+	image = view->priv->image;
+
+	file = eom_image_get_file (image);
+	uris[0] = g_file_get_uri (file);
+	uris[1] = NULL;
+
+	gtk_selection_data_set_uris (data, uris);
+
+	g_free (uris[0]);
+	g_object_unref (file);
+}
+
+GtkWidget*
+eom_scroll_view_new (void)
+{
+	GtkWidget *widget;
+
+	widget = g_object_new (EOM_TYPE_SCROLL_VIEW,
+			       "can-focus", TRUE,
+			       "row-homogeneous", FALSE,
+			       "column-homogeneous", FALSE,
+			       NULL);
+
+
+	return widget;
+}
+
+static gboolean
+view_on_button_press_event_cb (GtkWidget *widget, GdkEventButton *event,
+			       gpointer user_data)
+{
+    EomScrollView *view = EOM_SCROLL_VIEW (widget);
+
+    /* Ignore double-clicks and triple-clicks */
+    if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+    {
+	    gtk_menu_popup_at_pointer (GTK_MENU (view->priv->menu),
+	                               (const GdkEvent*) event);
+
+	    return TRUE;
+    }
+
+    return FALSE;
+}
+
+void
+eom_scroll_view_set_popup (EomScrollView *view,
+			   GtkMenu *menu)
+{
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+	g_return_if_fail (view->priv->menu == NULL);
+
+	view->priv->menu = g_object_ref (GTK_WIDGET (menu));
+
+	gtk_menu_attach_to_widget (GTK_MENU (view->priv->menu),
+				   GTK_WIDGET (view),
+				   NULL);
+
+	g_signal_connect (G_OBJECT (view), "button_press_event",
+			  G_CALLBACK (view_on_button_press_event_cb), NULL);
+}
+
+static gboolean
+_eom_gdk_rgba_equal0 (const GdkRGBA *a, const GdkRGBA *b)
+{
+	if (a == NULL || b == NULL)
+		return (a == b);
+
+	return gdk_rgba_equal (a, b);
+}
+
+static gboolean
+_eom_replace_gdk_rgba (GdkRGBA **dest, const GdkRGBA *src)
+{
+	GdkRGBA *old = *dest;
+
+	if (_eom_gdk_rgba_equal0 (old, src))
+		return FALSE;
+
+	if (old != NULL)
+		gdk_rgba_free (old);
+
+	*dest = (src) ? gdk_rgba_copy (src) : NULL;
+
+	return TRUE;
+}
+
+static void
+_eom_scroll_view_update_bg_color (EomScrollView *view)
+{
+	EomScrollViewPrivate *priv = view->priv;
+
+	if (priv->transp_style == EOM_TRANSP_BACKGROUND
+	    && priv->background_surface != NULL) {
+		/* Delete the SVG background to have it recreated with
+		 * the correct color during the next SVG redraw */
+		cairo_surface_destroy (priv->background_surface);
+		priv->background_surface = NULL;
+	}
+
+	gtk_widget_queue_draw (priv->display);
+}
+
+void
+eom_scroll_view_set_background_color (EomScrollView *view,
+				      const GdkRGBA *color)
+{
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	if (_eom_replace_gdk_rgba (&view->priv->background_color, color))
+		_eom_scroll_view_update_bg_color (view);
+}
+
+void
+eom_scroll_view_override_bg_color (EomScrollView *view,
+				   const GdkRGBA *color)
+{
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	if (_eom_replace_gdk_rgba (&view->priv->override_bg_color, color))
+		_eom_scroll_view_update_bg_color (view);
+}
+
+void
+eom_scroll_view_set_use_bg_color (EomScrollView *view, gboolean use)
+{
+	EomScrollViewPrivate *priv;
+
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	priv = view->priv;
+
+	if (use != priv->use_bg_color) {
+		priv->use_bg_color = use;
+
+		_eom_scroll_view_update_bg_color (view);
+
+		g_object_notify (G_OBJECT (view), "use-background-color");
+	}
+}
+
+void
+eom_scroll_view_set_scroll_wheel_zoom (EomScrollView *view,
+				       gboolean       scroll_wheel_zoom)
+{
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+	if (view->priv->scroll_wheel_zoom != scroll_wheel_zoom) {
+		view->priv->scroll_wheel_zoom = scroll_wheel_zoom;
+		g_object_notify (G_OBJECT (view), "scrollwheel-zoom");
+	}
+}
+
+void
+eom_scroll_view_set_zoom_multiplier (EomScrollView *view,
+				     gdouble        zoom_multiplier)
+{
+	g_return_if_fail (EOM_IS_SCROLL_VIEW (view));
+
+        view->priv->zoom_multiplier = 1.0 + zoom_multiplier;
+
+	g_object_notify (G_OBJECT (view), "zoom-multiplier");
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/2.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/2.html new file mode 100644 index 0000000..9a53950 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/2.html @@ -0,0 +1,2136 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
/*
+ *  Copyright (C) 2002-2004 Marco Pesenti Gritti
+ *  Copyright (C) 2004 Christian Persch
+ *
+ *  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, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *  $Id: egg-toolbars-model.c 929 2009-02-19 14:49:56Z friemann $
+ */
+
+#include "config.h"
+
+#include "egg-toolbars-model.h"
+#include "eggtypebuiltins.h"
+#include "eggmarshalers.h"
+
+#include <unistd.h>
+#include <string.h>
+#include <libxml/tree.h>
+#include <gdk/gdk.h>
+
+static void egg_toolbars_model_finalize   (GObject               *object);
+
+enum
+{
+  ITEM_ADDED,
+  ITEM_REMOVED,
+  TOOLBAR_ADDED,
+  TOOLBAR_CHANGED,
+  TOOLBAR_REMOVED,
+  LAST_SIGNAL
+};
+
+typedef struct
+{
+  char *name;
+  EggTbModelFlags flags;
+} EggToolbarsToolbar;
+
+typedef struct
+{
+  char *name;
+} EggToolbarsItem;
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct EggToolbarsModelPrivate
+{
+  GNode *toolbars;
+  GList *types;
+  GHashTable *flags;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (EggToolbarsModel, egg_toolbars_model, G_TYPE_OBJECT)
+
+static xmlDocPtr
+egg_toolbars_model_to_xml (EggToolbarsModel *model)
+{
+  GNode *l1, *l2, *tl;
+  GList *l3;
+  xmlDocPtr doc;
+
+  g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), NULL);
+
+  tl = model->priv->toolbars;
+
+  xmlIndentTreeOutput = TRUE;
+  doc = xmlNewDoc ((const xmlChar*) "1.0");
+  doc->children = xmlNewDocNode (doc, NULL, (const xmlChar*) "toolbars", NULL);
+
+  for (l1 = tl->children; l1 != NULL; l1 = l1->next)
+    {
+      xmlNodePtr tnode;
+      EggToolbarsToolbar *toolbar = l1->data;
+
+      tnode = xmlNewChild (doc->children, NULL, (const xmlChar*) "toolbar", NULL);
+      xmlSetProp (tnode, (const xmlChar*) "name", (const xmlChar*) toolbar->name);
+      xmlSetProp (tnode, (const xmlChar*) "hidden",
+		  (toolbar->flags&EGG_TB_MODEL_HIDDEN) ? (const xmlChar*) "true" : (const xmlChar*) "false");
+      xmlSetProp (tnode, (const xmlChar*) "editable",
+		  (toolbar->flags&EGG_TB_MODEL_NOT_EDITABLE) ? (const xmlChar*) "false" : (const xmlChar*) "true");
+
+      for (l2 = l1->children; l2 != NULL; l2 = l2->next)
+	{
+	  xmlNodePtr node;
+	  EggToolbarsItem *item = l2->data;
+
+          if (strcmp (item->name, "_separator") == 0)
+            {
+              node = xmlNewChild (tnode, NULL, (const xmlChar*) "separator", NULL);
+              continue;
+            }
+
+          node = xmlNewChild (tnode, NULL, (const xmlChar*) "toolitem", NULL);
+          xmlSetProp (node, (const xmlChar*) "name", (const xmlChar*) item->name);
+
+          /* Add 'data' nodes for each data type which can be written out for this
+           * item. Only write types which can be used to restore the data. */
+          for (l3 = model->priv->types; l3 != NULL; l3 = l3->next)
+            {
+              EggToolbarsItemType *type = l3->data;
+              if (type->get_name != NULL && type->get_data != NULL)
+                {
+                  xmlNodePtr dnode;
+                  char *tmp;
+
+                  tmp = type->get_data (type, item->name);
+                  if (tmp != NULL)
+                    {
+                      dnode = xmlNewTextChild (node, NULL, (const xmlChar*) "data", (const xmlChar*) tmp);
+                      g_free (tmp);
+
+                      tmp = gdk_atom_name (type->type);
+                      xmlSetProp (dnode, (const xmlChar*) "type", (const xmlChar*) tmp);
+                      g_free (tmp);
+                    }
+                }
+	    }
+	}
+    }
+
+  return doc;
+}
+
+static gboolean
+safe_save_xml (const char *xml_file, xmlDocPtr doc)
+{
+	char *tmp_file;
+	char *old_file;
+	gboolean old_exist;
+	gboolean retval = TRUE;
+
+	tmp_file = g_strconcat (xml_file, ".tmp", NULL);
+	old_file = g_strconcat (xml_file, ".old", NULL);
+
+	if (xmlSaveFormatFile (tmp_file, doc, 1) <= 0)
+	{
+		g_warning ("Failed to write XML data to %s", tmp_file);
+		goto failed;
+	}
+
+	old_exist = g_file_test (xml_file, G_FILE_TEST_EXISTS);
+
+	if (old_exist)
+	{
+		if (rename (xml_file, old_file) < 0)
+		{
+			g_warning ("Failed to rename %s to %s", xml_file, old_file);
+			retval = FALSE;
+			goto failed;
+		}
+	}
+
+	if (rename (tmp_file, xml_file) < 0)
+	{
+		g_warning ("Failed to rename %s to %s", tmp_file, xml_file);
+
+		if (rename (old_file, xml_file) < 0)
+		{
+			g_warning ("Failed to restore %s from %s", xml_file, tmp_file);
+		}
+		retval = FALSE;
+		goto failed;
+	}
+
+	if (old_exist)
+	{
+		if (unlink (old_file) < 0)
+		{
+			g_warning ("Failed to delete old file %s", old_file);
+		}
+	}
+
+	failed:
+	g_free (old_file);
+	g_free (tmp_file);
+
+	return retval;
+}
+
+void
+egg_toolbars_model_save_toolbars (EggToolbarsModel *model,
+				  const char *xml_file,
+				  const char *version)
+{
+  xmlDocPtr doc;
+  xmlNodePtr root;
+
+  g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
+
+  doc = egg_toolbars_model_to_xml (model);
+  root = xmlDocGetRootElement (doc);
+  xmlSetProp (root, (const xmlChar*) "version", (const xmlChar*) version);
+  safe_save_xml (xml_file, doc);
+  xmlFreeDoc (doc);
+}
+
+static gboolean
+is_unique (EggToolbarsModel *model,
+	   EggToolbarsItem *idata)
+{
+  EggToolbarsItem *idata2;
+  GNode *toolbar, *item;
+
+
+  for(toolbar = g_node_first_child (model->priv->toolbars);
+      toolbar != NULL; toolbar = g_node_next_sibling (toolbar))
+    {
+      for(item = g_node_first_child (toolbar);
+	  item != NULL; item = g_node_next_sibling (item))
+        {
+	  idata2 = item->data;
+
+	  if (idata != idata2 && strcmp (idata->name, idata2->name) == 0)
+	    {
+	      return FALSE;
+	    }
+	}
+    }
+
+  return TRUE;
+}
+
+static GNode *
+toolbar_node_new (const char *name)
+{
+  EggToolbarsToolbar *toolbar;
+
+  toolbar = g_new (EggToolbarsToolbar, 1);
+  toolbar->name = g_strdup (name);
+  toolbar->flags = 0;
+
+  return g_node_new (toolbar);
+}
+
+static GNode *
+item_node_new (const char *name, EggToolbarsModel *model)
+{
+  EggToolbarsItem *item;
+  int flags;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  item = g_new (EggToolbarsItem, 1);
+  item->name = g_strdup (name);
+
+  flags = GPOINTER_TO_INT (g_hash_table_lookup (model->priv->flags, item->name));
+  if ((flags & EGG_TB_MODEL_NAME_INFINITE) == 0)
+    g_hash_table_insert (model->priv->flags,
+			 g_strdup (item->name),
+			 GINT_TO_POINTER (flags | EGG_TB_MODEL_NAME_USED));
+
+  return g_node_new (item);
+}
+
+static void
+item_node_free (GNode *item_node, EggToolbarsModel *model)
+{
+  EggToolbarsItem *item = item_node->data;<--- Null pointer dereference<--- Dereferencing argument item_node that is null
+  int flags;
+
+  flags = GPOINTER_TO_INT (g_hash_table_lookup (model->priv->flags, item->name));
+  if ((flags & EGG_TB_MODEL_NAME_INFINITE) == 0 && is_unique (model, item))
+    g_hash_table_insert (model->priv->flags,
+			 g_strdup (item->name),
+			 GINT_TO_POINTER (flags & ~EGG_TB_MODEL_NAME_USED));
+
+  g_free (item->name);
+  g_free (item);
+
+  g_node_destroy (item_node);
+}
+
+static void
+toolbar_node_free (GNode *toolbar_node, EggToolbarsModel *model)
+{
+  EggToolbarsToolbar *toolbar = toolbar_node->data;<--- Null pointer dereference<--- Dereferencing argument toolbar_node that is null
+
+  g_node_children_foreach (toolbar_node, G_TRAVERSE_ALL,
+    			   (GNodeForeachFunc) item_node_free, model);
+
+  g_free (toolbar->name);
+  g_free (toolbar);
+
+  g_node_destroy (toolbar_node);
+}
+
+EggTbModelFlags
+egg_toolbars_model_get_flags (EggToolbarsModel *model,
+			      int               toolbar_position)
+{
+  GNode *toolbar_node;
+  EggToolbarsToolbar *toolbar;
+
+  toolbar_node = g_node_nth_child (model->priv->toolbars, toolbar_position);<--- Assignment 'toolbar_node=g_node_nth_child(model->priv->toolbars,toolbar_position)', assigned value is 0
+  g_return_val_if_fail (toolbar_node != NULL, 0);<--- Assuming that condition 'toolbar_node!=NULL' is not redundant
+
+  toolbar = toolbar_node->data;<--- Null pointer dereference
+
+  return toolbar->flags;
+}
+
+void
+egg_toolbars_model_set_flags (EggToolbarsModel *model,
+			      int               toolbar_position,
+			      EggTbModelFlags   flags)
+{
+  GNode *toolbar_node;
+  EggToolbarsToolbar *toolbar;
+
+  toolbar_node = g_node_nth_child (model->priv->toolbars, toolbar_position);<--- Assignment 'toolbar_node=g_node_nth_child(model->priv->toolbars,toolbar_position)', assigned value is 0
+  g_return_if_fail (toolbar_node != NULL);<--- Assuming that condition 'toolbar_node!=NULL' is not redundant
+
+  toolbar = toolbar_node->data;<--- Null pointer dereference
+
+  toolbar->flags = flags;
+
+  g_signal_emit (G_OBJECT (model), signals[TOOLBAR_CHANGED],
+		 0, toolbar_position);
+}
+
+
+char *
+egg_toolbars_model_get_data (EggToolbarsModel *model,
+                             GdkAtom           type,
+                             const char       *name)
+{
+  EggToolbarsItemType *t;
+  char *data = NULL;
+  GList *l;
+
+  if (type == GDK_NONE || type == gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE))
+    {
+      g_return_val_if_fail (name != NULL, NULL);
+      g_return_val_if_fail (*name != 0,   NULL);
+      return strdup (name);
+    }
+
+  for (l = model->priv->types; l != NULL; l = l->next)
+    {
+      t = l->data;
+      if (t->type == type && t->get_data != NULL)
+        {
+          data = t->get_data (t, name);
+	  if (data != NULL) break;
+        }
+    }
+
+  return data;
+}
+
+char *
+egg_toolbars_model_get_name (EggToolbarsModel *model,
+                             GdkAtom           type,
+                             const char       *data,
+                             gboolean          create)
+{
+  EggToolbarsItemType *t;
+  char *name = NULL;
+  GList *l;
+
+  if (type == GDK_NONE || type == gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE))
+    {
+      g_return_val_if_fail (data, NULL);
+      g_return_val_if_fail (*data, NULL);
+      return strdup (data);
+    }
+
+  if (create)
+    {
+      for (l = model->priv->types; name == NULL && l != NULL; l = l->next)
+        {
+          t = l->data;
+          if (t->type == type && t->new_name != NULL)
+            name = t->new_name (t, data);
+        }
+
+      return name;
+    }
+  else
+    {
+      for (l = model->priv->types; name == NULL && l != NULL; l = l->next)
+        {
+          t = l->data;
+          if (t->type == type && t->get_name != NULL)
+            name = t->get_name (t, data);
+        }
+
+      return name;
+    }
+}
+
+static gboolean
+impl_add_item (EggToolbarsModel    *model,
+	       int		    toolbar_position,
+	       int		    position,
+	       const char          *name)
+{
+  GNode *parent_node;
+  GNode *child_node;
+  int real_position;
+
+  g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), FALSE);
+  g_return_val_if_fail (name != NULL, FALSE);
+
+  parent_node = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  child_node = item_node_new (name, model);
+  g_node_insert (parent_node, position, child_node);
+
+  real_position = g_node_child_position (parent_node, child_node);
+
+  g_signal_emit (G_OBJECT (model), signals[ITEM_ADDED], 0,
+		 toolbar_position, real_position);
+
+  return TRUE;
+}
+
+gboolean
+egg_toolbars_model_add_item (EggToolbarsModel *model,
+			     int	       toolbar_position,
+			     int               position,
+			     const char       *name)
+{
+  EggToolbarsModelClass *klass = EGG_TOOLBARS_MODEL_GET_CLASS (model);
+  return klass->add_item (model, toolbar_position, position, name);
+}
+
+int
+egg_toolbars_model_add_toolbar (EggToolbarsModel *model,
+				int               position,
+				const char       *name)
+{
+  GNode *node;
+  int real_position;
+
+  g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), -1);
+
+  node = toolbar_node_new (name);
+  g_node_insert (model->priv->toolbars, position, node);
+
+  real_position = g_node_child_position (model->priv->toolbars, node);
+
+  g_signal_emit (G_OBJECT (model), signals[TOOLBAR_ADDED],
+		 0, real_position);
+
+  return g_node_child_position (model->priv->toolbars, node);
+}
+
+static char *
+parse_data_list (EggToolbarsModel *model,
+		 xmlNodePtr        child,
+                 gboolean          create)
+{
+  char *name = NULL;
+  while (child && name == NULL)
+    {
+      if (xmlStrEqual (child->name, (const xmlChar*) "data"))
+        {
+          xmlChar *type = xmlGetProp (child, (const xmlChar*) "type");
+          xmlChar *data = xmlNodeGetContent (child);
+
+          if (type != NULL)
+            {
+              GdkAtom atom = gdk_atom_intern ((const char*) type, TRUE);
+              name = egg_toolbars_model_get_name (model, atom, (const char*) data, create);
+            }
+
+          xmlFree (type);
+          xmlFree (data);
+        }
+
+      child = child->next;
+    }
+
+  return name;
+}
+
+static void
+parse_item_list (EggToolbarsModel *model,
+		 xmlNodePtr        child,
+		 int               position)
+{
+  while (child)
+    {
+      if (xmlStrEqual (child->name, (const xmlChar*) "toolitem"))
+	{
+          char *name;
+
+          /* Try to get the name using the data elements first,
+             as they are more 'portable' or 'persistent'. */
+          name = parse_data_list (model, child->children, FALSE);
+          if (name == NULL)
+            {
+              name = parse_data_list (model, child->children, TRUE);
+            }
+
+          /* If that fails, try to use the name. */
+          if (name == NULL)
+            {
+              xmlChar *type = xmlGetProp (child, (const xmlChar*) "type");
+              xmlChar *data = xmlGetProp (child, (const xmlChar*) "name");
+              GdkAtom  atom = type ? gdk_atom_intern ((const char*) type, TRUE) : GDK_NONE;
+
+              /* If an old format, try to use it. */
+              name = egg_toolbars_model_get_name (model, atom, (const char*) data, FALSE);
+              if (name == NULL)
+                {
+                  name = egg_toolbars_model_get_name (model, atom, (const char*) data, TRUE);
+                }
+
+              xmlFree (type);
+              xmlFree (data);
+            }
+
+          if (name != NULL)
+            {
+              egg_toolbars_model_add_item (model, position, -1, name);
+              g_free (name);
+            }
+	}
+      else if (xmlStrEqual (child->name, (const xmlChar*) "separator"))
+	{
+          egg_toolbars_model_add_item (model, position, -1, "_separator");
+	}
+
+      child = child->next;
+    }
+}
+
+static void
+parse_toolbars (EggToolbarsModel *model,
+		xmlNodePtr        child)
+{
+  while (child)
+    {
+      if (xmlStrEqual (child->name, (const xmlChar*) "toolbar"))
+	{
+	  xmlChar *string;
+	  int position;
+          EggTbModelFlags flags;
+
+	  string = xmlGetProp (child, (const xmlChar*) "name");
+	  position = egg_toolbars_model_add_toolbar (model, -1, (const char*) string);
+          flags = egg_toolbars_model_get_flags (model, position);
+	  xmlFree (string);
+
+	  string = xmlGetProp (child, (const xmlChar*) "editable");
+          if (string && xmlStrEqual (string, (const xmlChar*) "false"))
+            flags |= EGG_TB_MODEL_NOT_EDITABLE;
+	  xmlFree (string);
+
+	  string = xmlGetProp (child, (const xmlChar*) "hidden");
+          if (string && xmlStrEqual (string, (const xmlChar*) "true"))
+            flags |= EGG_TB_MODEL_HIDDEN;
+	  xmlFree (string);
+
+	  string = xmlGetProp (child, (const xmlChar*) "style");
+	  if (string && xmlStrEqual (string, (const xmlChar*) "icons-only"))
+            flags |= EGG_TB_MODEL_ICONS;
+	  xmlFree (string);
+
+          egg_toolbars_model_set_flags (model, position, flags);
+
+	  parse_item_list (model, child->children, position);
+	}
+
+      child = child->next;
+    }
+}
+
+gboolean
+egg_toolbars_model_load_toolbars (EggToolbarsModel *model,
+				  const char *xml_file)
+{
+  xmlDocPtr doc;
+  xmlNodePtr root;
+
+  g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), FALSE);
+
+  if (!xml_file || !g_file_test (xml_file, G_FILE_TEST_EXISTS)) return FALSE;
+
+  doc = xmlParseFile (xml_file);
+  if (doc == NULL)
+  {
+    g_warning ("Failed to load XML data from %s", xml_file);
+    return FALSE;
+  }
+  root = xmlDocGetRootElement (doc);
+
+  parse_toolbars (model, root->children);
+
+  xmlFreeDoc (doc);
+
+  return TRUE;
+}
+
+static void
+parse_available_list (EggToolbarsModel *model,
+		      xmlNodePtr        child)
+{
+  gint flags;
+
+  while (child)
+    {
+      if (xmlStrEqual (child->name, (const xmlChar*) "toolitem"))
+	{
+	  xmlChar *name;
+
+	  name = xmlGetProp (child, (const xmlChar*) "name");
+	  flags = egg_toolbars_model_get_name_flags
+	    (model, (const char*)name);
+	  egg_toolbars_model_set_name_flags
+	    (model, (const char*)name, flags | EGG_TB_MODEL_NAME_KNOWN);
+	  xmlFree (name);
+	}
+      child = child->next;
+    }
+}
+
+static void
+parse_names (EggToolbarsModel *model,
+	     xmlNodePtr        child)
+{
+  while (child)
+    {
+      if (xmlStrEqual (child->name, (const xmlChar*) "available"))
+	{
+	  parse_available_list (model, child->children);
+	}
+
+      child = child->next;
+    }
+}
+
+gboolean
+egg_toolbars_model_load_names (EggToolbarsModel *model,
+			       const char *xml_file)
+{
+  xmlDocPtr doc;
+  xmlNodePtr root;
+
+  g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), FALSE);
+
+  if (!xml_file || !g_file_test (xml_file, G_FILE_TEST_EXISTS)) return FALSE;
+
+  doc = xmlParseFile (xml_file);
+  if (doc == NULL)
+  {
+    g_warning ("Failed to load XML data from %s", xml_file);
+    return FALSE;
+  }
+  root = xmlDocGetRootElement (doc);
+
+  parse_names (model, root->children);
+
+  xmlFreeDoc (doc);
+
+  return TRUE;
+}
+
+static void
+egg_toolbars_model_class_init (EggToolbarsModelClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = egg_toolbars_model_finalize;
+
+  klass->add_item = impl_add_item;
+
+  signals[ITEM_ADDED] =
+    g_signal_new ("item_added",
+		  G_OBJECT_CLASS_TYPE (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (EggToolbarsModelClass, item_added),
+		  NULL, NULL, _egg_marshal_VOID__INT_INT,
+		  G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
+  signals[TOOLBAR_ADDED] =
+    g_signal_new ("toolbar_added",
+		  G_OBJECT_CLASS_TYPE (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_added),
+		  NULL, NULL, g_cclosure_marshal_VOID__INT,
+		  G_TYPE_NONE, 1, G_TYPE_INT);
+  signals[ITEM_REMOVED] =
+    g_signal_new ("item_removed",
+		  G_OBJECT_CLASS_TYPE (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (EggToolbarsModelClass, item_removed),
+		  NULL, NULL, _egg_marshal_VOID__INT_INT,
+		  G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
+  signals[TOOLBAR_REMOVED] =
+    g_signal_new ("toolbar_removed",
+		  G_OBJECT_CLASS_TYPE (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_removed),
+		  NULL, NULL, g_cclosure_marshal_VOID__INT,
+		  G_TYPE_NONE, 1, G_TYPE_INT);
+  signals[TOOLBAR_CHANGED] =
+    g_signal_new ("toolbar_changed",
+		  G_OBJECT_CLASS_TYPE (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_changed),
+		  NULL, NULL, g_cclosure_marshal_VOID__INT,
+		  G_TYPE_NONE, 1, G_TYPE_INT);
+}
+
+static void
+egg_toolbars_model_init (EggToolbarsModel *model)
+{
+  model->priv = egg_toolbars_model_get_instance_private (model);
+
+  model->priv->toolbars = g_node_new (NULL);
+  model->priv->flags = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  egg_toolbars_model_set_name_flags (model, "_separator",
+				     EGG_TB_MODEL_NAME_KNOWN |
+				     EGG_TB_MODEL_NAME_INFINITE);
+}
+
+static void
+egg_toolbars_model_finalize (GObject *object)
+{
+  EggToolbarsModel *model = EGG_TOOLBARS_MODEL (object);
+
+  g_node_children_foreach (model->priv->toolbars, G_TRAVERSE_ALL,
+    			   (GNodeForeachFunc) toolbar_node_free, model);
+  g_node_destroy (model->priv->toolbars);
+  g_hash_table_destroy (model->priv->flags);
+
+  G_OBJECT_CLASS (egg_toolbars_model_parent_class)->finalize (object);
+}
+
+EggToolbarsModel *
+egg_toolbars_model_new (void)
+{
+  return EGG_TOOLBARS_MODEL (g_object_new (EGG_TYPE_TOOLBARS_MODEL, NULL));
+}
+
+void
+egg_toolbars_model_remove_toolbar (EggToolbarsModel   *model,
+				   int                 position)
+{
+  GNode *node;
+  EggTbModelFlags flags;
+
+  g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
+
+  flags = egg_toolbars_model_get_flags (model, position);
+
+  if (!(flags & EGG_TB_MODEL_NOT_REMOVABLE))
+    {
+      node = g_node_nth_child (model->priv->toolbars, position);<--- Assignment 'node=g_node_nth_child(model->priv->toolbars,position)', assigned value is 0<--- Assignment 'node=g_node_nth_child(model->priv->toolbars,position)', assigned value is 0
+      g_return_if_fail (node != NULL);<--- Assuming that condition 'node!=NULL' is not redundant<--- Assuming that condition 'node!=NULL' is not redundant
+
+      toolbar_node_free (node, model);<--- Calling function 'toolbar_node_free', 1st argument 'node' value is 0<--- Calling function toolbar_node_free, 1st argument is null
+
+      g_signal_emit (G_OBJECT (model), signals[TOOLBAR_REMOVED],
+		     0, position);
+    }
+}
+
+void
+egg_toolbars_model_remove_item (EggToolbarsModel *model,
+				int               toolbar_position,
+				int               position)
+{
+  GNode *node, *toolbar;
+
+  g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
+
+  toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  g_return_if_fail (toolbar != NULL);
+
+  node = g_node_nth_child (toolbar, position);<--- Assignment 'node=g_node_nth_child(toolbar,position)', assigned value is 0<--- Assignment 'node=g_node_nth_child(toolbar,position)', assigned value is 0
+  g_return_if_fail (node != NULL);<--- Assuming that condition 'node!=NULL' is not redundant<--- Assuming that condition 'node!=NULL' is not redundant
+
+  item_node_free (node, model);<--- Calling function 'item_node_free', 1st argument 'node' value is 0<--- Calling function item_node_free, 1st argument is null
+
+  g_signal_emit (G_OBJECT (model), signals[ITEM_REMOVED], 0,
+		 toolbar_position, position);
+}
+
+void
+egg_toolbars_model_move_item (EggToolbarsModel *model,
+			      int               toolbar_position,
+			      int               position,
+			      int		new_toolbar_position,
+			      int		new_position)
+{
+  GNode *node, *toolbar, *new_toolbar;
+
+  g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
+
+  toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  g_return_if_fail (toolbar != NULL);
+
+  new_toolbar = g_node_nth_child (model->priv->toolbars, new_toolbar_position);
+  g_return_if_fail (new_toolbar != NULL);
+
+  node = g_node_nth_child (toolbar, position);
+  g_return_if_fail (node != NULL);
+
+  g_node_unlink (node);
+
+  g_signal_emit (G_OBJECT (model), signals[ITEM_REMOVED], 0,
+		 toolbar_position, position);
+
+  g_node_insert (new_toolbar, new_position, node);
+
+  g_signal_emit (G_OBJECT (model), signals[ITEM_ADDED], 0,
+		 new_toolbar_position, new_position);
+}
+
+void
+egg_toolbars_model_delete_item (EggToolbarsModel *model,
+				const char       *name)
+{
+  EggToolbarsItem *idata;
+  EggToolbarsToolbar *tdata;
+  GNode *toolbar, *item, *next;
+  int tpos, ipos;
+
+  g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
+
+  toolbar = g_node_first_child (model->priv->toolbars);
+  tpos = 0;
+
+  while (toolbar != NULL)
+    {
+      item = g_node_first_child (toolbar);
+      ipos = 0;
+
+      /* Don't delete toolbars that were already empty */
+      if (item == NULL)
+        {
+	  toolbar = g_node_next_sibling (toolbar);
+	  continue;
+        }
+
+      while (item != NULL)
+        {
+	  next = g_node_next_sibling (item);
+	  idata = item->data;
+	  if (strcmp (idata->name, name) == 0)
+	    {
+	      item_node_free (item, model);
+	      g_signal_emit (G_OBJECT (model),
+			     signals[ITEM_REMOVED],
+			     0, tpos, ipos);
+	    }
+	  else
+	    {
+	      ipos++;
+	    }
+
+	  item = next;
+        }
+
+      next = g_node_next_sibling (toolbar);
+      tdata = toolbar->data;
+      if (!(tdata->flags & EGG_TB_MODEL_NOT_REMOVABLE) &&
+	  g_node_first_child (toolbar) == NULL)
+        {
+	  toolbar_node_free (toolbar, model);
+
+	  g_signal_emit (G_OBJECT (model),
+			 signals[TOOLBAR_REMOVED],
+			 0, tpos);
+        }
+      else
+        {
+	  tpos++;
+        }
+
+      toolbar = next;
+    }
+}
+
+int
+egg_toolbars_model_n_items (EggToolbarsModel *model,
+			    int               toolbar_position)
+{
+  GNode *toolbar;
+
+  toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  g_return_val_if_fail (toolbar != NULL, -1);
+
+  return g_node_n_children (toolbar);
+}
+
+const char *
+egg_toolbars_model_item_nth (EggToolbarsModel *model,
+			     int	       toolbar_position,
+			     int               position)
+{
+  GNode *toolbar;
+  GNode *item;
+  EggToolbarsItem *idata;
+
+  toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  g_return_val_if_fail (toolbar != NULL, NULL);
+
+  item = g_node_nth_child (toolbar, position);<--- Assignment 'item=g_node_nth_child(toolbar,position)', assigned value is 0
+  g_return_val_if_fail (item != NULL, NULL);<--- Assuming that condition 'item!=NULL' is not redundant
+
+  idata = item->data;<--- Null pointer dereference
+  return idata->name;
+}
+
+int
+egg_toolbars_model_n_toolbars (EggToolbarsModel *model)
+{
+  return g_node_n_children (model->priv->toolbars);<--- Dereferencing argument model that is null
+}
+
+const char *
+egg_toolbars_model_toolbar_nth (EggToolbarsModel *model,
+				int               position)
+{
+  GNode *toolbar;
+  EggToolbarsToolbar *tdata;
+
+  toolbar = g_node_nth_child (model->priv->toolbars, position);<--- Assignment 'toolbar=g_node_nth_child(model->priv->toolbars,position)', assigned value is 0
+  g_return_val_if_fail (toolbar != NULL, NULL);<--- Assuming that condition 'toolbar!=NULL' is not redundant
+
+  tdata = toolbar->data;<--- Null pointer dereference
+
+  return tdata->name;
+}
+
+GList *
+egg_toolbars_model_get_types (EggToolbarsModel *model)
+{
+  return model->priv->types;
+}
+
+void
+egg_toolbars_model_set_types (EggToolbarsModel *model, GList *types)
+{
+  model->priv->types = types;
+}
+
+static void
+fill_avail_array (gpointer key, gpointer value, GPtrArray *array)
+{
+  int flags = GPOINTER_TO_INT (value);
+  if ((flags & EGG_TB_MODEL_NAME_KNOWN) && !(flags & EGG_TB_MODEL_NAME_USED))
+      g_ptr_array_add (array, key);
+}
+
+GPtrArray *
+egg_toolbars_model_get_name_avail (EggToolbarsModel *model)
+{
+  GPtrArray *array = g_ptr_array_new ();
+  g_hash_table_foreach (model->priv->flags, (GHFunc) fill_avail_array, array);
+  return array;
+}
+
+gint
+egg_toolbars_model_get_name_flags (EggToolbarsModel *model, const char *name)
+{
+  return GPOINTER_TO_INT (g_hash_table_lookup (model->priv->flags, name));
+}
+
+void
+egg_toolbars_model_set_name_flags (EggToolbarsModel *model, const char *name, gint flags)
+{
+  g_hash_table_insert (model->priv->flags, g_strdup (name), GINT_TO_POINTER (flags));
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/20.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/20.html new file mode 100644 index 0000000..1cdfbba --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/20.html @@ -0,0 +1,2352 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
/* Eye Of Mate - Thumbnail View
+ *
+ * Copyright (C) 2006-2008 The Free Software Foundation
+ *
+ * Author: Claudio Saavedra <csaavedra@gnome.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "eom-thumb-view.h"
+#include "eom-list-store.h"
+#include "eom-image.h"
+#include "eom-job-queue.h"
+
+#ifdef HAVE_EXIF
+#include "eom-exif-util.h"
+#include <libexif/exif-data.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+#include <string.h>
+
+enum {
+  PROP_0,
+  PROP_ORIENTATION
+};
+
+#define EOM_THUMB_VIEW_SPACING 0
+
+static EomImage* eom_thumb_view_get_image_from_path (EomThumbView      *thumbview,
+						     GtkTreePath       *path);
+
+static void      eom_thumb_view_popup_menu          (EomThumbView      *widget,
+						     GdkEventButton    *event);
+
+static void      eom_thumb_view_update_columns (EomThumbView *view);
+
+static gboolean
+thumbview_on_query_tooltip_cb (GtkWidget  *widget,
+			       gint        x,
+			       gint        y,
+			       gboolean    keyboard_mode,
+			       GtkTooltip *tooltip,
+			       gpointer    user_data);
+static void
+thumbview_on_parent_set_cb (GtkWidget *widget,
+			    GtkWidget *old_parent,
+			    gpointer   user_data);
+
+static void
+thumbview_on_drag_data_get_cb (GtkWidget        *widget,
+			       GdkDragContext   *drag_context,
+			       GtkSelectionData *data,
+			       guint             info,
+			       guint             time,
+			       gpointer          user_data);
+
+struct _EomThumbViewPrivate {
+	gint start_thumb; /* the first visible thumbnail */
+	gint end_thumb;   /* the last visible thumbnail  */
+	GtkWidget *menu;  /* a contextual menu for thumbnails */
+	GtkCellRenderer *pixbuf_cell;
+	gint visible_range_changed_id;
+
+	GtkOrientation orientation;
+	gint n_images;
+	gulong image_add_id;
+	gulong image_removed_id;
+};
+
+G_DEFINE_TYPE_WITH_CODE (EomThumbView, eom_thumb_view, GTK_TYPE_ICON_VIEW,
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL) \
+			 G_ADD_PRIVATE (EomThumbView));
+
+/* Drag 'n Drop */
+
+static void
+eom_thumb_view_constructed (GObject *object)
+{
+	EomThumbView *thumbview;
+
+	if (G_OBJECT_CLASS (eom_thumb_view_parent_class)->constructed)
+		G_OBJECT_CLASS (eom_thumb_view_parent_class)->constructed (object);
+
+	thumbview = EOM_THUMB_VIEW (object);
+
+	thumbview->priv->pixbuf_cell = gtk_cell_renderer_pixbuf_new ();
+
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (thumbview),
+				    thumbview->priv->pixbuf_cell,
+				    FALSE);
+
+	g_object_set (thumbview->priv->pixbuf_cell,
+	              "height", 100,
+	              "width", 115,
+	              "yalign", 0.5,
+	              "xalign", 0.5,
+	              NULL);
+
+	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (thumbview),
+					thumbview->priv->pixbuf_cell,
+					"pixbuf", EOM_LIST_STORE_THUMBNAIL,
+					NULL);
+
+	gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (thumbview),
+					  GTK_SELECTION_MULTIPLE);
+
+	gtk_icon_view_set_column_spacing (GTK_ICON_VIEW (thumbview),
+					  EOM_THUMB_VIEW_SPACING);
+
+	gtk_icon_view_set_row_spacing (GTK_ICON_VIEW (thumbview),
+				       EOM_THUMB_VIEW_SPACING);
+
+	g_object_set (thumbview, "has-tooltip", TRUE, NULL);
+
+	g_signal_connect (thumbview,
+			  "query-tooltip",
+			  G_CALLBACK (thumbview_on_query_tooltip_cb),
+			  NULL);
+
+	thumbview->priv->start_thumb = 0;
+	thumbview->priv->end_thumb = 0;
+	thumbview->priv->menu = NULL;
+
+	g_signal_connect (G_OBJECT (thumbview), "parent-set",
+			  G_CALLBACK (thumbview_on_parent_set_cb), NULL);
+
+	gtk_icon_view_enable_model_drag_source (GTK_ICON_VIEW (thumbview), 0,
+						NULL, 0,
+						GDK_ACTION_COPY |
+						GDK_ACTION_MOVE |
+						GDK_ACTION_LINK |
+						GDK_ACTION_ASK);
+	gtk_drag_source_add_uri_targets (GTK_WIDGET (thumbview));
+
+	g_signal_connect (G_OBJECT (thumbview), "drag-data-get",
+			  G_CALLBACK (thumbview_on_drag_data_get_cb), NULL);
+}
+
+static void
+eom_thumb_view_dispose (GObject *object)
+{
+	EomThumbViewPrivate *priv = EOM_THUMB_VIEW (object)->priv;
+	GtkTreeModel *model;
+
+	if (priv->visible_range_changed_id != 0) {
+		g_source_remove (priv->visible_range_changed_id);
+		priv->visible_range_changed_id = 0;
+	}
+
+	model = gtk_icon_view_get_model (GTK_ICON_VIEW (object));
+
+	if (model && priv->image_add_id != 0) {
+		g_signal_handler_disconnect (model, priv->image_add_id);
+		priv->image_add_id = 0;
+	}
+
+	if (model && priv->image_removed_id) {
+		g_signal_handler_disconnect (model, priv->image_removed_id);
+		priv->image_removed_id = 0;
+	}
+
+	G_OBJECT_CLASS (eom_thumb_view_parent_class)->dispose (object);
+}
+
+static void
+eom_thumb_view_get_property (GObject    *object,
+			     guint       prop_id,
+			     GValue     *value,
+			     GParamSpec *pspec)
+{
+	EomThumbView *view = EOM_THUMB_VIEW (object);
+
+	switch (prop_id)
+	{
+	case PROP_ORIENTATION:
+		g_value_set_enum (value, view->priv->orientation);
+		break;
+
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+eom_thumb_view_set_property (GObject      *object,
+			     guint         prop_id,
+			     const GValue *value,
+			     GParamSpec   *pspec)
+{
+	EomThumbView *view = EOM_THUMB_VIEW (object);
+
+	switch (prop_id)
+	{
+	case PROP_ORIENTATION:
+		view->priv->orientation = g_value_get_enum (value);
+		eom_thumb_view_update_columns (view);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+eom_thumb_view_class_init (EomThumbViewClass *class)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+	gobject_class->constructed = eom_thumb_view_constructed;
+	gobject_class->dispose = eom_thumb_view_dispose;
+	gobject_class->get_property = eom_thumb_view_get_property;
+	gobject_class->set_property = eom_thumb_view_set_property;
+
+	g_object_class_override_property (gobject_class, PROP_ORIENTATION,
+	                                  "orientation");
+}
+
+static void
+eom_thumb_view_clear_range (EomThumbView *thumbview,
+			    const gint start_thumb,
+			    const gint end_thumb)
+{
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	EomListStore *store = EOM_LIST_STORE (gtk_icon_view_get_model (GTK_ICON_VIEW (thumbview)));
+	gint thumb = start_thumb;
+	gboolean result;
+
+	g_assert (start_thumb <= end_thumb);
+
+	path = gtk_tree_path_new_from_indices (start_thumb, -1);
+	for (result = gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
+	     result && thumb <= end_thumb;
+	     result = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter), thumb++) {
+		eom_list_store_thumbnail_unset (store, &iter);
+	}
+	gtk_tree_path_free (path);
+}
+
+static void
+eom_thumb_view_add_range (EomThumbView *thumbview,
+			  const gint start_thumb,
+			  const gint end_thumb)
+{
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	EomListStore *store = EOM_LIST_STORE (gtk_icon_view_get_model (GTK_ICON_VIEW (thumbview)));
+	gint thumb = start_thumb;
+	gboolean result;
+
+	g_assert (start_thumb <= end_thumb);
+
+	path = gtk_tree_path_new_from_indices (start_thumb, -1);
+	for (result = gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
+	     result && thumb <= end_thumb;
+	     result = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter), thumb++) {
+		eom_list_store_thumbnail_set (store, &iter);
+	}
+	gtk_tree_path_free (path);
+}
+
+static void
+eom_thumb_view_update_visible_range (EomThumbView *thumbview,
+				     const gint start_thumb,
+				     const gint end_thumb)
+{
+	EomThumbViewPrivate *priv = thumbview->priv;
+	int old_start_thumb, old_end_thumb;
+
+	old_start_thumb= priv->start_thumb;
+	old_end_thumb = priv->end_thumb;
+
+	if (start_thumb == old_start_thumb &&
+	    end_thumb == old_end_thumb) {
+		return;
+	}
+
+	if (old_start_thumb < start_thumb)
+		eom_thumb_view_clear_range (thumbview, old_start_thumb, MIN (start_thumb - 1, old_end_thumb));
+
+	if (old_end_thumb > end_thumb)
+		eom_thumb_view_clear_range (thumbview, MAX (end_thumb + 1, old_start_thumb), old_end_thumb);
+
+	eom_thumb_view_add_range (thumbview, start_thumb, end_thumb);
+
+	priv->start_thumb = start_thumb;
+	priv->end_thumb = end_thumb;
+}
+
+static gboolean
+visible_range_changed_cb (EomThumbView *thumbview)
+{
+	GtkTreePath *path1, *path2;
+
+	thumbview->priv->visible_range_changed_id = 0;
+
+	if (!gtk_icon_view_get_visible_range (GTK_ICON_VIEW (thumbview), &path1, &path2)) {
+		return FALSE;
+	}
+
+	if (path1 == NULL) {
+		path1 = gtk_tree_path_new_first ();
+	}
+	if (path2 == NULL) {
+		gint n_items = gtk_tree_model_iter_n_children (gtk_icon_view_get_model (GTK_ICON_VIEW (thumbview)), NULL);
+		path2 = gtk_tree_path_new_from_indices (n_items - 1 , -1);
+	}
+
+	eom_thumb_view_update_visible_range (thumbview, gtk_tree_path_get_indices (path1) [0],
+					     gtk_tree_path_get_indices (path2) [0]);
+
+	gtk_tree_path_free (path1);
+	gtk_tree_path_free (path2);
+
+	return FALSE;
+}
+
+static void
+eom_thumb_view_visible_range_changed (EomThumbView *thumbview)
+{
+	if (thumbview->priv->visible_range_changed_id == 0) {
+		g_idle_add ((GSourceFunc)visible_range_changed_cb, thumbview);
+	}
+
+}
+
+static void
+thumbview_on_visible_range_changed_cb (EomThumbView *thumbview,
+				       gpointer user_data)
+{
+	eom_thumb_view_visible_range_changed (thumbview);
+}
+
+static void
+thumbview_on_adjustment_changed_cb (EomThumbView *thumbview,
+				    gpointer user_data)
+{
+	eom_thumb_view_visible_range_changed (thumbview);
+}
+
+static void
+thumbview_on_parent_set_cb (GtkWidget *widget,
+			    GtkWidget *old_parent,
+			    gpointer   user_data)
+{
+	EomThumbView *thumbview = EOM_THUMB_VIEW (widget);
+	GtkScrolledWindow *sw;
+	GtkAdjustment *hadjustment;
+	GtkAdjustment *vadjustment;
+
+	GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (thumbview));
+	if (!GTK_IS_SCROLLED_WINDOW (parent)) {
+		return;
+	}
+
+	/* if we have been set to a ScrolledWindow, we connect to the callback
+	   to set and unset thumbnails. */
+	sw = GTK_SCROLLED_WINDOW (parent);
+	hadjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (sw));
+	vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw));
+
+	/* when scrolling */
+	g_signal_connect_data (G_OBJECT (hadjustment), "value-changed",
+			       G_CALLBACK (thumbview_on_visible_range_changed_cb),
+			       thumbview, NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+	g_signal_connect_data (G_OBJECT (vadjustment), "value-changed",
+			       G_CALLBACK (thumbview_on_visible_range_changed_cb),
+			       thumbview, NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+
+	/* when the adjustment is changed, ie. probably we have new images added. */
+	g_signal_connect_data (G_OBJECT (hadjustment), "changed",
+			       G_CALLBACK (thumbview_on_adjustment_changed_cb),
+			       thumbview, NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+	g_signal_connect_data (G_OBJECT (vadjustment), "changed",
+			       G_CALLBACK (thumbview_on_adjustment_changed_cb),
+			       thumbview, NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+
+	/* when resizing the scrolled window */
+	g_signal_connect_swapped (G_OBJECT (sw), "size-allocate",
+				  G_CALLBACK (thumbview_on_visible_range_changed_cb),
+				  thumbview);
+}
+
+static gboolean
+thumbview_on_button_press_event_cb (GtkWidget *thumbview, GdkEventButton *event,
+				    gpointer user_data)
+{
+	GtkTreePath *path;
+
+	/* Ignore double-clicks and triple-clicks */
+	if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+	{
+		path = gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (thumbview),
+						      (gint) event->x, (gint) event->y);
+		if (path == NULL) {
+			return FALSE;
+		}
+
+		if (!gtk_icon_view_path_is_selected (GTK_ICON_VIEW (thumbview), path) ||
+		    eom_thumb_view_get_n_selected (EOM_THUMB_VIEW (thumbview)) != 1) {
+			gtk_icon_view_unselect_all (GTK_ICON_VIEW (thumbview));
+			gtk_icon_view_select_path (GTK_ICON_VIEW (thumbview), path);
+			gtk_icon_view_set_cursor (GTK_ICON_VIEW (thumbview), path, NULL, FALSE);
+		}
+		eom_thumb_view_popup_menu (EOM_THUMB_VIEW (thumbview), event);
+
+		gtk_tree_path_free (path);
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+thumbview_on_drag_data_get_cb (GtkWidget        *widget,
+			       GdkDragContext   *drag_context,
+			       GtkSelectionData *data,
+			       guint             info,
+			       guint             time,
+			       gpointer          user_data)
+{
+	GList *list;
+	GList *node;
+	EomImage *image;
+	GFile *file;
+	gchar **uris = NULL;
+	gint i = 0, n_images;
+
+	list = eom_thumb_view_get_selected_images (EOM_THUMB_VIEW (widget));
+	n_images = eom_thumb_view_get_n_selected (EOM_THUMB_VIEW (widget));
+
+	uris = g_new (gchar *, n_images + 1);
+
+	for (node = list; node != NULL; node = node->next, i++) {
+		image = EOM_IMAGE (node->data);
+		file = eom_image_get_file (image);
+		uris[i] = g_file_get_uri (file);
+		g_object_unref (image);
+		g_object_unref (file);
+	}
+	uris[i] = NULL;
+
+	gtk_selection_data_set_uris (data, uris);
+	g_strfreev (uris);
+	g_list_free (list);
+}
+
+static gchar *
+thumbview_get_tooltip_string (EomImage *image)
+{
+	gchar *bytes;
+	char *type_str;
+	gint width, height;
+	GFile *file;
+	GFileInfo *file_info;
+	const char *mime_str;
+	gchar *tooltip_string;
+#ifdef HAVE_EXIF
+	ExifData *exif_data;
+#endif
+
+	bytes = g_format_size (eom_image_get_bytes (image));
+
+	eom_image_get_size (image, &width, &height);
+
+	file = eom_image_get_file (image);
+	file_info = g_file_query_info (file,
+				       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+				       0, NULL, NULL);
+	g_object_unref (file);
+	if (file_info == NULL) {
+		g_free (bytes);
+		return NULL;
+	}
+
+	mime_str = g_file_info_get_content_type (file_info);
+
+	if (G_UNLIKELY (mime_str == NULL)) {
+		g_free (bytes);
+		g_object_unref (image);
+		return NULL;
+	}
+
+	type_str = g_content_type_get_description (mime_str);
+	g_object_unref (file_info);
+
+	if (width > -1 && height > -1) {
+		tooltip_string = g_markup_printf_escaped ("<b><big>%s</big></b>\n"
+							  "%i x %i %s\n"
+							  "%s\n"
+							  "%s",
+							  eom_image_get_caption (image),
+							  width,
+							  height,
+							  ngettext ("pixel",
+								    "pixels",
+								    height),
+							  bytes,
+							  type_str);
+	} else {
+		tooltip_string = g_markup_printf_escaped ("<b><big>%s</big></b>\n"
+							  "%s\n"
+							  "%s",
+							  eom_image_get_caption (image),
+							  bytes,
+							  type_str);
+
+	}
+
+#ifdef HAVE_EXIF
+	exif_data = (ExifData *) eom_image_get_exif_info (image);
+
+	if (exif_data) {
+		gchar *extra_info, *tmp, *date;
+		/* The EXIF standard says that the DATE_TIME tag is
+		 * 20 bytes long. A 32-byte buffer should be large enough. */
+		gchar time_buffer[32];
+
+		date = eom_exif_util_format_date (
+			eom_exif_data_get_value (exif_data, EXIF_TAG_DATE_TIME_ORIGINAL, time_buffer, 32));
+
+		if (date) {
+			extra_info = g_strdup_printf ("\n%s %s", _("Taken on"), date);
+
+			tmp = g_strconcat (tooltip_string, extra_info, NULL);
+
+			g_free (date);
+			g_free (extra_info);
+			g_free (tooltip_string);
+
+			tooltip_string = tmp;
+		}
+		exif_data_unref (exif_data);
+	}
+#endif
+
+	g_free (type_str);
+	g_free (bytes);
+
+	return tooltip_string;
+}
+
+static void
+on_data_loaded_cb (EomJob *job, gpointer data)
+{
+	if (!job->error) {
+		gtk_tooltip_trigger_tooltip_query (gdk_display_get_default());
+	}
+}
+
+static gboolean
+thumbview_on_query_tooltip_cb (GtkWidget  *widget,
+			       gint        x,
+			       gint        y,
+			       gboolean    keyboard_mode,
+			       GtkTooltip *tooltip,
+			       gpointer    user_data)
+{
+	GtkTreePath *path;
+	EomImage *image;
+	gchar *tooltip_string;
+	EomImageData data = 0;
+
+	if (!gtk_icon_view_get_tooltip_context (GTK_ICON_VIEW (widget),
+						&x, &y, keyboard_mode,
+						NULL, &path, NULL)) {
+		return FALSE;
+	}
+
+	image = eom_thumb_view_get_image_from_path (EOM_THUMB_VIEW (widget),
+						    path);
+	gtk_tree_path_free (path);
+
+	if (image == NULL) {
+		return FALSE;
+	}
+
+	if (!eom_image_has_data (image, EOM_IMAGE_DATA_EXIF) &&
+            eom_image_get_metadata_status (image) == EOM_IMAGE_METADATA_NOT_READ) {
+		data = EOM_IMAGE_DATA_EXIF;
+	}
+
+	if (!eom_image_has_data (image, EOM_IMAGE_DATA_DIMENSION)) {
+		data |= EOM_IMAGE_DATA_DIMENSION;
+	}
+
+	if (data) {
+		EomJob *job;
+
+		job = eom_job_load_new (image, data);
+		g_signal_connect (G_OBJECT (job), "finished",
+				  G_CALLBACK (on_data_loaded_cb),
+				  widget);
+		eom_job_queue_add_job (job);
+		g_object_unref (image);
+		g_object_unref (job);
+		return FALSE;
+	}
+
+	tooltip_string = thumbview_get_tooltip_string (image);
+	g_object_unref (image);
+
+	if (tooltip_string == NULL) {
+		return FALSE;
+	}
+
+	gtk_tooltip_set_markup (tooltip, tooltip_string);
+	g_free (tooltip_string);
+
+	return TRUE;
+}
+
+static void
+eom_thumb_view_init (EomThumbView *thumbview)
+{
+	thumbview->priv = eom_thumb_view_get_instance_private (thumbview);
+
+	thumbview->priv->visible_range_changed_id = 0;
+	thumbview->priv->image_add_id = 0;
+	thumbview->priv->image_removed_id = 0;
+}
+
+/**
+ * eom_thumb_view_new:
+ *
+ * Creates a new #EomThumbView object.
+ *
+ * Returns: a newly created #EomThumbView.
+ **/
+GtkWidget *
+eom_thumb_view_new (void)
+{
+	EomThumbView *thumbview;
+
+	thumbview = g_object_new (EOM_TYPE_THUMB_VIEW, NULL);
+
+	return GTK_WIDGET (thumbview);
+}
+
+static void
+eom_thumb_view_update_columns (EomThumbView *view)
+{
+	EomThumbViewPrivate *priv;
+
+	g_return_if_fail (EOM_IS_THUMB_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+			gtk_icon_view_set_columns (GTK_ICON_VIEW (view),
+			                           priv->n_images);
+}
+
+static void
+eom_thumb_view_row_inserted_cb (GtkTreeModel    *tree_model,
+                                GtkTreePath     *path,
+                                GtkTreeIter     *iter,
+                                EomThumbView    *view)
+{
+	EomThumbViewPrivate *priv = view->priv;
+
+	priv->n_images++;
+	eom_thumb_view_update_columns (view);
+}
+
+static void
+eom_thumb_view_row_deleted_cb (GtkTreeModel    *tree_model,
+                               GtkTreePath     *path,
+                               EomThumbView    *view)
+{
+	EomThumbViewPrivate *priv = view->priv;
+
+	priv->n_images--;
+	eom_thumb_view_update_columns (view);
+}
+
+/**
+ * eom_thumb_view_set_model:
+ * @thumbview: A #EomThumbView.
+ * @store: A #EomListStore.
+ *
+ * Sets the #EomListStore to be used with @thumbview. If an initial image
+ * was set during @store creation, its thumbnail will be selected and visible.
+ *
+ **/
+void
+eom_thumb_view_set_model (EomThumbView *thumbview, EomListStore *store)
+{
+	gint index;
+	EomThumbViewPrivate *priv;
+	GtkTreeModel *existing;
+
+	g_return_if_fail (EOM_IS_THUMB_VIEW (thumbview));
+	g_return_if_fail (EOM_IS_LIST_STORE (store));
+
+	priv = thumbview->priv;
+
+	existing = gtk_icon_view_get_model (GTK_ICON_VIEW (thumbview));
+
+	if (existing != NULL) {
+		if (priv->image_add_id != 0) {
+			g_signal_handler_disconnect (existing,
+			                             priv->image_add_id);
+		}
+		if (priv->image_removed_id != 0) {
+			g_signal_handler_disconnect (existing,
+			                             priv->image_removed_id);
+
+		}
+	}
+
+	priv->image_add_id = g_signal_connect (G_OBJECT (store), "row-inserted",
+	                            G_CALLBACK (eom_thumb_view_row_inserted_cb),
+	                            thumbview);
+	priv->image_removed_id = g_signal_connect (G_OBJECT (store),
+	                             "row-deleted",
+	                             G_CALLBACK (eom_thumb_view_row_deleted_cb),
+	                             thumbview);
+
+	thumbview->priv->n_images = eom_list_store_length (store);
+
+	index = eom_list_store_get_initial_pos (store);
+
+	gtk_icon_view_set_model (GTK_ICON_VIEW (thumbview),
+	                         GTK_TREE_MODEL (store));
+
+	eom_thumb_view_update_columns (thumbview);
+
+	if (index >= 0) {
+		GtkTreePath *path = gtk_tree_path_new_from_indices (index, -1);
+		gtk_icon_view_select_path (GTK_ICON_VIEW (thumbview), path);
+		gtk_icon_view_set_cursor (GTK_ICON_VIEW (thumbview), path, NULL, FALSE);
+		gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (thumbview), path, FALSE, 0, 0);
+		gtk_tree_path_free (path);
+	}
+}
+
+/**
+ * eom_thumb_view_set_item_height:
+ * @thumbview: A #EomThumbView.
+ * @height: The desired height.
+ *
+ * Sets the height of each thumbnail in @thumbview.
+ *
+ **/
+void
+eom_thumb_view_set_item_height (EomThumbView *thumbview, gint height)
+{
+	g_return_if_fail (EOM_IS_THUMB_VIEW (thumbview));
+
+	g_object_set (thumbview->priv->pixbuf_cell,
+	              "height", height,
+	              NULL);
+}
+
+static void
+eom_thumb_view_get_n_selected_helper (GtkIconView *thumbview,
+				      GtkTreePath *path,
+				      gpointer data)
+{
+	/* data is of type (guint *) */
+	(*(guint *) data) ++;
+}
+
+/**
+ * eom_thumb_view_get_n_selected:
+ * @thumbview: An #EomThumbView.
+ *
+ * Gets the number of images that are currently selected in @thumbview.
+ *
+ * Returns: the number of selected images in @thumbview.
+ **/
+guint
+eom_thumb_view_get_n_selected (EomThumbView *thumbview)
+{
+	guint count = 0;
+	gtk_icon_view_selected_foreach (GTK_ICON_VIEW (thumbview),
+					eom_thumb_view_get_n_selected_helper,
+					(&count));
+	return count;
+}
+
+/**
+ * eom_thumb_view_get_image_from_path:
+ * @thumbview: A #EomThumbView.
+ * @path: A #GtkTreePath pointing to a #EomImage in the model for @thumbview.
+ *
+ * Gets the #EomImage stored in @thumbview's #EomListStore at the position indicated
+ * by @path.
+ *
+ * Returns: (transfer full): A #EomImage.
+ **/
+static EomImage *
+eom_thumb_view_get_image_from_path (EomThumbView *thumbview, GtkTreePath *path)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	EomImage *image;
+
+	model = gtk_icon_view_get_model (GTK_ICON_VIEW (thumbview));
+	gtk_tree_model_get_iter (model, &iter, path);
+
+	gtk_tree_model_get (model, &iter,
+			    EOM_LIST_STORE_EOM_IMAGE, &image,
+			    -1);
+
+	return image;
+}
+
+/**
+ * eom_thumb_view_get_first_selected_image:
+ * @thumbview: A #EomThumbView.
+ *
+ * Returns the first selected image. Note that the returned #EomImage
+ * is not ensured to be really the first selected image in @thumbview, but
+ * generally, it will be.
+ *
+ * Returns: (transfer full): A #EomImage.
+ **/
+EomImage *
+eom_thumb_view_get_first_selected_image (EomThumbView *thumbview)
+{
+	/* The returned list is not sorted! We need to find the
+	   smaller tree path value => tricky and expensive. Do we really need this?
+	*/
+	EomImage *image;
+	GtkTreePath *path;
+	GList *list = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (thumbview));
+
+	if (list == NULL) {
+		return NULL;
+	}
+
+	path = (GtkTreePath *) (list->data);
+
+	image = eom_thumb_view_get_image_from_path (thumbview, path);
+
+	g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
+
+	return image;
+}
+
+/**
+ * eom_thumb_view_get_selected_images:
+ * @thumbview: A #EomThumbView.
+ *
+ * Gets a list with the currently selected images. Note that a new reference is
+ * hold for each image and the list must be freed with g_list_free().
+ *
+ * Returns: (element-type EomImage) (transfer full): A newly allocated list of #EomImage's.
+ **/
+GList *
+eom_thumb_view_get_selected_images (EomThumbView *thumbview)
+{
+	GList *l, *item;
+	GList *list = NULL;
+
+	GtkTreePath *path;
+
+	l = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (thumbview));
+
+	for (item = l; item != NULL; item = item->next) {
+		path = (GtkTreePath *) item->data;
+		list = g_list_prepend (list, eom_thumb_view_get_image_from_path (thumbview, path));
+		gtk_tree_path_free (path);
+	}
+
+	g_list_free (l);
+	list = g_list_reverse (list);
+
+	return list;
+}
+
+/**
+ * eom_thumb_view_set_current_image:
+ * @thumbview: A #EomThumbView.
+ * @image: The image to be selected.
+ * @deselect_other: Whether to deselect currently selected images.
+ *
+ * Changes the status of a image, marking it as currently selected.
+ * If @deselect_other is %TRUE, all other selected images will be
+ * deselected.
+ *
+ **/
+void
+eom_thumb_view_set_current_image (EomThumbView *thumbview, EomImage *image,
+				  gboolean deselect_other)
+{
+	GtkTreePath *path;
+	EomListStore *store;
+	gint pos;
+
+	store = EOM_LIST_STORE (gtk_icon_view_get_model (GTK_ICON_VIEW (thumbview)));
+	pos = eom_list_store_get_pos_by_image (store, image);
+	path = gtk_tree_path_new_from_indices (pos, -1);
+
+	if (path == NULL) {
+		return;
+	}
+
+	if (deselect_other) {
+		gtk_icon_view_unselect_all (GTK_ICON_VIEW (thumbview));
+	}
+
+	gtk_icon_view_select_path (GTK_ICON_VIEW (thumbview), path);
+	gtk_icon_view_set_cursor (GTK_ICON_VIEW (thumbview), path, NULL, FALSE);
+	gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (thumbview), path, FALSE, 0, 0);
+
+	gtk_tree_path_free (path);
+}
+
+/**
+ * eom_thumb_view_select_single:
+ * @thumbview: A #EomThumbView.
+ * @change: A #EomThumbViewSelectionChange, describing the
+ * desired selection change.
+ *
+ * Changes the current selection according to a single movement
+ * described by #EomThumbViewSelectionChange. If there are no
+ * thumbnails currently selected, one is selected according to the
+ * natural selection according to the #EomThumbViewSelectionChange
+ * used, p.g., when %EOM_THUMB_VIEW_SELECT_RIGHT is the selected change,
+ * the first thumbnail will be selected.
+ *
+ **/
+void
+eom_thumb_view_select_single (EomThumbView *thumbview,
+			      EomThumbViewSelectionChange change)
+{
+  	GtkTreePath *path = NULL;
+	GtkTreeModel *model;
+	GList *list;
+	gint n_items;
+
+	g_return_if_fail (EOM_IS_THUMB_VIEW (thumbview));
+
+	model = gtk_icon_view_get_model (GTK_ICON_VIEW (thumbview));
+
+	n_items = eom_list_store_length (EOM_LIST_STORE (model));
+
+	if (n_items == 0) {
+		return;
+	}
+
+	if (eom_thumb_view_get_n_selected (thumbview) == 0) {
+		switch (change) {
+		case EOM_THUMB_VIEW_SELECT_CURRENT:
+			break;
+		case EOM_THUMB_VIEW_SELECT_RIGHT:
+		case EOM_THUMB_VIEW_SELECT_FIRST:
+			path = gtk_tree_path_new_first ();
+			break;
+		case EOM_THUMB_VIEW_SELECT_LEFT:
+		case EOM_THUMB_VIEW_SELECT_LAST:
+			path = gtk_tree_path_new_from_indices (n_items - 1, -1);
+			break;
+		case EOM_THUMB_VIEW_SELECT_RANDOM:
+			path = gtk_tree_path_new_from_indices (g_random_int_range (0, n_items), -1);
+			break;
+		}
+	} else {
+		list = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (thumbview));
+		path = gtk_tree_path_copy ((GtkTreePath *) list->data);
+		g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
+
+		gtk_icon_view_unselect_all (GTK_ICON_VIEW (thumbview));
+
+		switch (change) {
+		case EOM_THUMB_VIEW_SELECT_CURRENT:
+			break;
+		case EOM_THUMB_VIEW_SELECT_LEFT:
+			if (!gtk_tree_path_prev (path)) {
+				gtk_tree_path_free (path);
+				path = gtk_tree_path_new_from_indices (n_items - 1, -1);
+			}
+			break;
+		case EOM_THUMB_VIEW_SELECT_RIGHT:
+			if (gtk_tree_path_get_indices (path) [0] == n_items - 1) {
+				gtk_tree_path_free (path);
+				path = gtk_tree_path_new_first ();
+			} else {
+				gtk_tree_path_next (path);
+			}
+			break;
+		case EOM_THUMB_VIEW_SELECT_FIRST:
+			gtk_tree_path_free (path);
+			path = gtk_tree_path_new_first ();
+			break;
+		case EOM_THUMB_VIEW_SELECT_LAST:
+			gtk_tree_path_free (path);
+			path = gtk_tree_path_new_from_indices (n_items - 1, -1);
+			break;
+		case EOM_THUMB_VIEW_SELECT_RANDOM:
+			gtk_tree_path_free (path);
+			path = gtk_tree_path_new_from_indices (g_random_int_range (0, n_items), -1);
+			break;
+		}
+	}
+
+	gtk_icon_view_select_path (GTK_ICON_VIEW (thumbview), path);
+	gtk_icon_view_set_cursor (GTK_ICON_VIEW (thumbview), path, NULL, FALSE);
+	gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (thumbview), path, FALSE, 0, 0);
+	gtk_tree_path_free (path);
+}
+
+
+/**
+ * eom_thumb_view_set_thumbnail_popup:
+ * @thumbview: An #EomThumbView.
+ * @menu: A #GtkMenu.
+ *
+ * Set the contextual menu to be used with the thumbnails in the
+ * widget. This can be done only once.
+ *
+ **/
+void
+eom_thumb_view_set_thumbnail_popup (EomThumbView *thumbview,
+				    GtkMenu      *menu)
+{
+	g_return_if_fail (EOM_IS_THUMB_VIEW (thumbview));
+	g_return_if_fail (thumbview->priv->menu == NULL);
+
+	thumbview->priv->menu = g_object_ref (GTK_WIDGET (menu));
+
+	gtk_menu_attach_to_widget (GTK_MENU (thumbview->priv->menu),
+				   GTK_WIDGET (thumbview),
+				   NULL);
+
+	g_signal_connect (G_OBJECT (thumbview), "button_press_event",
+			  G_CALLBACK (thumbview_on_button_press_event_cb), NULL);
+
+}
+
+
+static void
+eom_thumb_view_popup_menu (EomThumbView *thumbview, GdkEventButton *event)
+{
+	g_return_if_fail (event != NULL);
+
+	gtk_menu_popup_at_pointer (GTK_MENU (thumbview->priv->menu),
+	                           (const GdkEvent*) event);
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/21.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/21.html new file mode 100644 index 0000000..1794055 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/21.html @@ -0,0 +1,2148 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <string.h>
+#include <glib.h>
+
+#include "eom-uri-converter.h"
+#include "eom-pixbuf-util.h"
+
+enum {
+	PROP_0,
+	PROP_CONVERT_SPACES,
+	PROP_SPACE_CHARACTER,
+	PROP_COUNTER_START,
+	PROP_COUNTER_N_DIGITS,
+	PROP_N_IMAGES
+};
+
+typedef struct {
+	EomUCType  type;
+	union {
+		char    *string;  /* if type == EOM_UC_STRING */
+		gulong  counter;  /* if type == EOM_UC_COUNTER */
+	} data;
+} EomUCToken;
+
+
+struct _EomURIConverterPrivate {
+	GFile           *base_file;
+	GList           *token_list;
+	char            *suffix;
+	GdkPixbufFormat *img_format;
+	gboolean        requires_exif;
+
+	/* options */
+	gboolean convert_spaces;
+	gchar    space_character;
+	gulong   counter_start;
+	guint    counter_n_digits;
+};
+
+static void eom_uri_converter_set_property (GObject      *object,
+					    guint         property_id,
+					    const GValue *value,
+					    GParamSpec   *pspec);
+
+static void eom_uri_converter_get_property (GObject    *object,
+					    guint       property_id,
+					    GValue     *value,
+					    GParamSpec *pspec);
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomURIConverter, eom_uri_converter, G_TYPE_OBJECT)
+
+static void
+free_token (gpointer data)
+{
+	EomUCToken *token = (EomUCToken*) data;
+
+	if (token->type == EOM_UC_STRING) {
+		g_free (token->data.string);
+	}
+
+	g_slice_free (EomUCToken, token);
+}
+
+static void
+eom_uri_converter_dispose (GObject *object)
+{
+	EomURIConverter *instance = EOM_URI_CONVERTER (object);
+	EomURIConverterPrivate *priv;
+
+	priv = instance->priv;
+
+	if (priv->base_file) {
+		g_object_unref (priv->base_file);
+		priv->base_file = NULL;
+	}
+
+	if (priv->token_list) {
+		g_list_free_full (priv->token_list, free_token);
+		priv->token_list = NULL;
+	}
+
+	if (priv->suffix) {
+		g_free (priv->suffix);
+		priv->suffix = NULL;
+	}
+
+
+	G_OBJECT_CLASS (eom_uri_converter_parent_class)->dispose (object);
+}
+
+static void
+eom_uri_converter_init (EomURIConverter *conv)
+{
+	EomURIConverterPrivate *priv;
+
+	priv = conv->priv = eom_uri_converter_get_instance_private (conv);
+
+	priv->convert_spaces   = FALSE;
+	priv->space_character  = '_';
+	priv->counter_start    = 0;
+	priv->counter_n_digits = 1;
+	priv->requires_exif     = FALSE;
+}
+
+static void
+eom_uri_converter_class_init (EomURIConverterClass *klass)
+{
+	GObjectClass *object_class = (GObjectClass*) klass;
+
+	object_class->dispose = eom_uri_converter_dispose;
+
+        /* GObjectClass */
+        object_class->set_property = eom_uri_converter_set_property;
+        object_class->get_property = eom_uri_converter_get_property;
+
+        /* Properties */
+        g_object_class_install_property (
+                object_class,
+                PROP_CONVERT_SPACES,
+                g_param_spec_boolean ("convert-spaces", NULL, NULL,
+				      FALSE, G_PARAM_READWRITE));
+
+        g_object_class_install_property (
+                object_class,
+                PROP_SPACE_CHARACTER,
+                g_param_spec_char ("space-character", NULL, NULL,
+				   ' ', '~', '_', G_PARAM_READWRITE));
+
+       g_object_class_install_property (
+                object_class,
+                PROP_COUNTER_START,
+                g_param_spec_ulong ("counter-start", NULL, NULL,
+                                   0,
+                                   G_MAXULONG,
+                                   1,
+                                   G_PARAM_READWRITE));
+
+       g_object_class_install_property (
+                object_class,
+                PROP_COUNTER_N_DIGITS,
+                g_param_spec_uint ("counter-n-digits", NULL, NULL,
+				  1,
+				  G_MAXUINT,
+				  1,
+				  G_PARAM_READWRITE));
+
+
+       g_object_class_install_property (
+                object_class,
+                PROP_N_IMAGES,
+                g_param_spec_uint ("n-images", NULL, NULL,
+				  1,
+				  G_MAXUINT,
+				  1,
+				  G_PARAM_WRITABLE));
+}
+
+GQuark
+eom_uc_error_quark (void)
+{
+	static GQuark q = 0;
+	if (q == 0)
+		q = g_quark_from_static_string ("eom-uri-converter-error-quark");
+
+	return q;
+}
+
+
+static void
+eom_uri_converter_set_property (GObject      *object,
+                                guint         property_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+	EomURIConverter *conv;
+	EomURIConverterPrivate *priv;
+
+        g_return_if_fail (EOM_IS_URI_CONVERTER (object));
+
+        conv = EOM_URI_CONVERTER (object);
+	priv = conv->priv;
+
+        switch (property_id)
+        {
+	case PROP_CONVERT_SPACES:
+		priv->convert_spaces = g_value_get_boolean (value);
+		break;
+
+	case PROP_SPACE_CHARACTER:
+		priv->space_character = g_value_get_schar (value);
+		break;
+
+	case PROP_COUNTER_START:
+	{
+		guint new_n_digits;
+
+		priv->counter_start = g_value_get_ulong (value);
+
+		new_n_digits = ceil (log10 (priv->counter_start + pow (10, priv->counter_n_digits) - 1));
+
+		if (new_n_digits != priv->counter_n_digits) {
+			priv->counter_n_digits = ceil (MIN (log10 (G_MAXULONG), new_n_digits));
+		}
+		break;
+	}
+
+	case PROP_COUNTER_N_DIGITS:
+		priv->counter_n_digits = ceil (MIN (log10 (G_MAXULONG), g_value_get_uint (value)));
+		break;
+
+	case PROP_N_IMAGES:
+		priv->counter_n_digits = ceil (MIN (log10 (G_MAXULONG),
+						    log10 (priv->counter_start + g_value_get_uint (value))));
+		break;
+
+        default:
+                g_assert_not_reached ();
+        }
+}
+
+static void
+eom_uri_converter_get_property (GObject    *object,
+                                guint       property_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+	EomURIConverter *conv;
+	EomURIConverterPrivate *priv;
+
+        g_return_if_fail (EOM_IS_URI_CONVERTER (object));
+
+        conv = EOM_URI_CONVERTER (object);
+	priv = conv->priv;
+
+        switch (property_id)
+        {
+	case PROP_CONVERT_SPACES:
+		g_value_set_boolean (value, priv->convert_spaces);
+		break;
+
+	case PROP_SPACE_CHARACTER:
+		g_value_set_schar (value, priv->space_character);
+		break;
+
+	case PROP_COUNTER_START:
+		g_value_set_ulong (value, priv->counter_start);
+		break;
+
+	case PROP_COUNTER_N_DIGITS:
+		g_value_set_uint (value, priv->counter_n_digits);
+		break;
+
+        default:
+                g_assert_not_reached ();
+	}
+}
+
+/* parser states */
+enum {
+	PARSER_NONE,
+	PARSER_STRING,
+	PARSER_TOKEN
+};
+
+static EomUCToken*
+create_token_string (const char *string, int substr_start, int substr_len)
+{
+	char *start_byte;
+	char *end_byte;
+	int n_bytes;
+	EomUCToken *token;
+
+	if (string == NULL) return NULL;
+	if (substr_len <= 0) return NULL;
+
+	start_byte = g_utf8_offset_to_pointer (string, substr_start);
+	end_byte = g_utf8_offset_to_pointer (string, substr_start + substr_len);
+
+	/* FIXME: is this right? */
+	n_bytes = end_byte - start_byte;
+
+	token = g_slice_new0 (EomUCToken);
+	token->type = EOM_UC_STRING;
+	token->data.string = g_new0 (char, n_bytes);
+	token->data.string = g_utf8_strncpy (token->data.string, start_byte, substr_len);
+
+	return token;
+}
+
+static EomUCToken*
+create_token_counter (int start_counter)
+{
+	EomUCToken *token;
+
+	token = g_slice_new0 (EomUCToken);
+	token->type = EOM_UC_COUNTER;
+	token->data.counter = 0;
+
+	return token;
+}
+
+static EomUCToken*
+create_token_other (EomUCType type)
+{
+	EomUCToken *token;
+
+	token = g_slice_new0 (EomUCToken);
+	token->type = type;
+
+	return token;
+}
+
+static GList*
+eom_uri_converter_parse_string (EomURIConverter *conv, const char *string)
+{
+	EomURIConverterPrivate *priv;
+	GList *list = NULL;
+	gulong len;
+	int i;
+	int state = PARSER_NONE;
+	int start = -1;
+	int substr_len = 0;
+	gunichar c;
+	const char *s;
+	EomUCToken *token;
+
+	g_return_val_if_fail (EOM_IS_URI_CONVERTER (conv), NULL);
+
+	priv = conv->priv;
+
+	if (string == NULL) return NULL;
+
+	if (!g_utf8_validate (string, -1, NULL))
+		return NULL;
+
+	len = g_utf8_strlen (string, -1);
+	s = string;
+
+	for (i = 0; i < len; i++) {
+		c = g_utf8_get_char (s);
+		token = NULL;
+
+		switch (state) {
+		case PARSER_NONE:
+			if (c == '%') {
+				start = -1;
+				state = PARSER_TOKEN;
+			} else {
+				start = i;
+				substr_len = 1;
+				state = PARSER_STRING;
+			}
+			break;
+
+		case PARSER_STRING:
+			if (c == '%') {
+				if (start != -1) {
+					token = create_token_string (string, start, substr_len);
+				}
+
+				state = PARSER_TOKEN;
+				start = -1;
+			} else {
+				substr_len++;
+			}
+			break;
+
+		case PARSER_TOKEN: {
+			EomUCType type = EOM_UC_END;
+
+			if (c == 'f') {
+				type = EOM_UC_FILENAME;
+			}
+			else if (c == 'n') {
+				type = EOM_UC_COUNTER;
+				token = create_token_counter (priv->counter_start);
+			}
+			else if (c == 'c') {
+				type = EOM_UC_COMMENT;
+			}
+			else if (c == 'd') {
+				type = EOM_UC_DATE;
+			}
+			else if (c == 't') {
+				type = EOM_UC_TIME;
+			}
+			else if (c == 'a') {
+				type = EOM_UC_DAY;
+			}
+			else if (c == 'm') {
+				type = EOM_UC_MONTH;
+			}
+			else if (c == 'y') {
+				type = EOM_UC_YEAR;
+			}
+			else if (c == 'h') {
+				type = EOM_UC_HOUR;
+			}
+			else if (c == 'i') {
+				type = EOM_UC_MINUTE;
+			}
+			else if (c == 's') {
+				type = EOM_UC_SECOND;
+			}
+
+			if (type != EOM_UC_END && token == NULL) {
+				token = create_token_other (type);
+				priv->requires_exif = TRUE;
+			}
+			state = PARSER_NONE;
+			break;
+		}
+		default:
+			g_assert_not_reached ();
+		}
+
+
+		if (token != NULL) {
+			list = g_list_append (list, token);
+		}
+
+		s = g_utf8_next_char (s);
+	}
+
+	if (state != PARSER_TOKEN && start >= 0) {
+		/* add remaining chars as string token */
+		list = g_list_append (list, create_token_string (string, start, substr_len));
+	}
+
+	return list;
+}
+
+void
+eom_uri_converter_print_list (EomURIConverter *conv)
+{
+	EomURIConverterPrivate *priv;
+	GList *it;
+
+	g_return_if_fail (EOM_URI_CONVERTER (conv));
+
+	priv = conv->priv;
+
+	for (it = priv->token_list; it != NULL; it = it->next) {
+		EomUCToken *token;
+		char *str;
+
+		token = (EomUCToken*) it->data;
+
+		switch (token->type) {
+		case EOM_UC_STRING:
+			str = g_strdup_printf ("string [%s]", token->data.string);
+			break;
+		case EOM_UC_FILENAME:
+			str = "filename";
+			break;
+		case EOM_UC_COUNTER:
+			str = g_strdup_printf ("counter [%lu]", token->data.counter);
+			break;
+		case EOM_UC_COMMENT:
+			str = "comment";
+			break;
+		case EOM_UC_DATE:
+			str = "date";
+			break;
+		case EOM_UC_TIME:
+			str = "time";
+			break;
+		case EOM_UC_DAY:
+			str = "day";
+			break;
+		case EOM_UC_MONTH:
+			str = "month";
+			break;
+		case EOM_UC_YEAR:
+			str = "year";
+			break;
+		case EOM_UC_HOUR:
+			str = "hour";
+			break;
+		case EOM_UC_MINUTE:
+			str = "minute";
+			break;
+		case EOM_UC_SECOND:
+			str = "second";
+			break;
+		default:
+			str = "unknown";
+			break;
+		}
+
+		g_print ("- %s\n", str);
+
+		if (token->type == EOM_UC_STRING || token->type == EOM_UC_COUNTER) {
+			g_free (str);
+		}
+	}
+}
+
+
+EomURIConverter*
+eom_uri_converter_new (GFile *base_file, GdkPixbufFormat *img_format, const char *format_str)
+{
+	EomURIConverter *conv;
+
+	g_return_val_if_fail (format_str != NULL, NULL);
+
+	conv = g_object_new (EOM_TYPE_URI_CONVERTER, NULL);
+
+	if (base_file != NULL) {
+		conv->priv->base_file  = g_object_ref (base_file);
+	}
+	else {
+		conv->priv->base_file = NULL;
+	}
+	conv->priv->img_format = img_format;
+	conv->priv->token_list = eom_uri_converter_parse_string (conv, format_str);
+
+	return conv;
+}
+
+static GFile*
+get_file_directory (EomURIConverter *conv, EomImage *image)
+{
+	GFile *file = NULL;
+	EomURIConverterPrivate *priv;
+
+	g_return_val_if_fail (EOM_IS_URI_CONVERTER (conv), NULL);
+	g_return_val_if_fail (EOM_IS_IMAGE (image), NULL);
+
+	priv = conv->priv;
+
+	if (priv->base_file != NULL) {
+		file = g_object_ref (priv->base_file);
+	}
+	else {
+		GFile *img_file;
+
+		img_file = eom_image_get_file (image);
+		g_assert (img_file != NULL);
+
+		file = g_file_get_parent (img_file);
+
+		g_object_unref (img_file);
+	}
+
+	return file;
+}
+
+static void
+split_filename (GFile *file, char **name, char **suffix)
+{
+	char *basename;
+	char *suffix_start;
+	guint len;
+
+	*name = NULL;
+	*suffix = NULL;
+
+        /* get unescaped string */
+	basename = g_file_get_basename (file);
+
+	/* FIXME: does this work for all locales? */
+	suffix_start = g_utf8_strrchr (basename, -1, '.');
+
+	if (suffix_start == NULL) { /* no suffix found */
+		*name = g_strdup (basename);
+	}
+	else {
+		len = (suffix_start - basename);
+		*name = g_strndup (basename, len);
+
+		len = strlen (basename) - len - 1;
+		*suffix = g_strndup (suffix_start+1, len);
+	}
+
+	g_free (basename);
+}
+
+static GString*
+append_filename (GString *str, EomImage *img)
+{
+	/* appends the name of the original file without
+	   filetype suffix */
+	GFile *img_file;
+	char *name;
+	char *suffix;
+	GString *result;
+
+	img_file = eom_image_get_file (img);
+	split_filename (img_file, &name, &suffix);
+
+	result = g_string_append (str, name);
+
+	g_free (name);
+	g_free (suffix);
+
+	g_object_unref (img_file);
+
+	return result;
+}
+
+static GString*
+append_counter (GString *str, gulong counter,  EomURIConverter *conv)
+{
+	EomURIConverterPrivate *priv;
+
+	priv = conv->priv;
+
+	g_string_append_printf (str, "%.*lu", priv->counter_n_digits, counter);
+
+	return str;
+}
+
+
+static void
+build_absolute_file (EomURIConverter *conv, EomImage *image, GString *str,  /* input  */
+		     GFile **file, GdkPixbufFormat **format)                /* output */
+{
+	GFile *dir_file;
+	EomURIConverterPrivate *priv;
+
+	*file = NULL;<--- Null pointer dereference
+	if (format != NULL)
+		*format = NULL;
+
+	g_return_if_fail (EOM_IS_URI_CONVERTER (conv));
+	g_return_if_fail (EOM_IS_IMAGE (image));
+	g_return_if_fail (file != NULL);<--- Assuming that condition 'file!=NULL' is not redundant
+	g_return_if_fail (str != NULL);
+
+	priv = conv->priv;
+
+	dir_file = get_file_directory (conv, image);
+	g_assert (dir_file != NULL);
+
+	if (priv->img_format == NULL) {
+		/* use same file type/suffix */
+		char *name;
+		char *old_suffix;
+		GFile *img_file;
+
+		img_file = eom_image_get_file (image);
+		split_filename (img_file, &name, &old_suffix);
+
+		g_assert (old_suffix != NULL);
+
+		g_string_append_unichar (str, '.');
+		g_string_append (str, old_suffix);
+
+		if (format != NULL)
+			*format = eom_pixbuf_get_format_by_suffix (old_suffix);
+
+		g_object_unref (img_file);
+	} else {
+		if (priv->suffix == NULL)
+			priv->suffix = eom_pixbuf_get_common_suffix (priv->img_format);
+
+		g_string_append_unichar (str, '.');
+		g_string_append (str, priv->suffix);
+
+		if (format != NULL)
+			*format = priv->img_format;
+	}
+
+	*file = g_file_get_child (dir_file, str->str);
+
+	g_object_unref (dir_file);
+}
+
+
+static GString*
+replace_remove_chars (GString *str, gboolean convert_spaces, gunichar space_char)
+{
+	GString *result;
+	guint len;
+	char *s;
+	int i;
+	gunichar c;
+
+	g_return_val_if_fail (str != NULL, NULL);
+
+	if (!g_utf8_validate (str->str, -1, NULL))
+	    return NULL;
+
+	result = g_string_new (NULL);
+
+	len = g_utf8_strlen (str->str, -1);
+	s = str->str;
+
+	for (i = 0; i < len; i++, s = g_utf8_next_char (s)) {
+		c = g_utf8_get_char (s);
+
+		if (c == '/') {
+			continue;
+		}
+		else if (g_unichar_isspace (c) && convert_spaces) {
+			result = g_string_append_unichar (result, space_char);
+		}
+		else {
+			result = g_string_append_unichar (result, c);
+		}
+	}
+
+	/* ensure maximum length of 250 characters */
+	len = MIN (result->len, 250);
+	result = g_string_truncate (result, len);
+
+	return result;
+}
+
+/*
+ * This function converts the uri of the EomImage object, according to the
+ * EomUCToken list. The absolute uri (converted filename appended to base uri)
+ * is returned in uri and the image format will be in the format pointer.
+ */
+gboolean
+eom_uri_converter_do (EomURIConverter *conv, EomImage *image,
+		      GFile **file, GdkPixbufFormat **format, GError **error)
+{
+	EomURIConverterPrivate *priv;
+	GList *it;
+	GString *str;
+	GString *repl_str;
+
+	g_return_val_if_fail (EOM_IS_URI_CONVERTER (conv), FALSE);
+
+	priv = conv->priv;
+
+	*file = NULL;
+	if (format != NULL)
+		*format = NULL;
+
+	str = g_string_new ("");
+
+	for (it = priv->token_list; it != NULL; it = it->next) {
+		EomUCToken *token = (EomUCToken*) it->data;
+
+		switch (token->type) {
+		case EOM_UC_STRING:
+			str = g_string_append (str, token->data.string);
+			break;
+
+		case EOM_UC_FILENAME:
+			str = append_filename (str, image);
+			break;
+
+		case EOM_UC_COUNTER: {
+			if (token->data.counter < priv->counter_start)
+				token->data.counter = priv->counter_start;
+
+			str = append_counter (str, token->data.counter++, conv);
+			break;
+		}
+#if 0
+		case EOM_UC_COMMENT:
+			str = g_string_append_printf ();
+			str = "comment";
+			break;
+		case EOM_UC_DATE:
+			str = "date";
+			break;
+		case EOM_UC_TIME:
+			str = "time";
+			break;
+		case EOM_UC_DAY:
+			str = "day";
+			break;
+		case EOM_UC_MONTH:
+			str = "month";
+			break;
+		case EOM_UC_YEAR:
+			str = "year";
+			break;
+		case EOM_UC_HOUR:
+			str = "hour";
+			break;
+		case EOM_UC_MINUTE:
+			str = "minute";
+			break;
+		case EOM_UC_SECOND:
+			str = "second";
+			break;
+#endif
+		default:
+		/* skip all others */
+
+			break;
+		}
+	}
+
+	repl_str = replace_remove_chars (str, priv->convert_spaces, priv->space_character);
+
+	if (repl_str->len > 0) {
+		build_absolute_file (conv, image, repl_str, file, format);
+	}
+
+	g_string_free (repl_str, TRUE);
+	g_string_free (str, TRUE);
+
+
+	return (*file != NULL);
+}
+
+
+char*
+eom_uri_converter_preview (const char *format_str, EomImage *img, GdkPixbufFormat *format,
+			   gulong counter, guint n_images,
+			   gboolean convert_spaces, gunichar space_char)
+{
+	GString *str;
+	GString *repl_str;
+	guint n_digits;
+	guint len;
+	int i;
+	const char *s;
+	gunichar c;
+	char *filename;
+	gboolean token_next;
+
+	g_return_val_if_fail (format_str != NULL, NULL);
+	g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+	if (n_images == 0) return NULL;
+
+	n_digits = ceil (MIN (log10 (G_MAXULONG), MAX (log10 (counter), log10 (n_images))));
+
+	if (!g_utf8_validate (format_str, -1, NULL))
+	    return NULL;
+
+	len = g_utf8_strlen (format_str, -1);
+	s = format_str;
+	token_next = FALSE;
+
+	str = g_string_new ("");
+
+	for (i = 0; i < len; i++, s = g_utf8_next_char (s)) {
+		c = g_utf8_get_char (s);
+
+		if (token_next) {
+			if (c == 'f') {
+				str = append_filename (str, img);
+			}
+			else if (c == 'n') {
+				g_string_append_printf (str, "%.*lu",
+							n_digits ,counter);
+
+			}
+#if 0                   /* ignore the rest for now */
+			else if (c == 'c') {
+				type = EOM_UC_COMMENT;
+			}
+			else if (c == 'd') {
+				type = EOM_UC_DATE;
+			}
+			else if (c == 't') {
+				type = EOM_UC_TIME;
+			}
+			else if (c == 'a') {
+				type = EOM_UC_DAY;
+			}
+			else if (c == 'm') {
+				type = EOM_UC_MONTH;
+			}
+			else if (c == 'y') {
+				type = EOM_UC_YEAR;
+			}
+			else if (c == 'h') {
+				type = EOM_UC_HOUR;
+			}
+			else if (c == 'i') {
+				type = EOM_UC_MINUTE;
+			}
+			else if (c == 's') {
+				type = EOM_UC_SECOND;
+			}
+#endif
+			token_next = FALSE;
+		}
+		else if (c == '%') {
+			token_next = TRUE;
+		}
+		else {
+			str = g_string_append_unichar (str, c);
+		}
+	}
+
+
+	filename = NULL;
+	repl_str = replace_remove_chars (str, convert_spaces, space_char);
+
+	if (repl_str->len > 0) {
+		if (format == NULL) {
+			/* use same file type/suffix */
+			char *name;
+			char *old_suffix;
+			GFile *img_file;
+
+			img_file = eom_image_get_file (img);
+			split_filename (img_file, &name, &old_suffix);
+
+			g_assert (old_suffix != NULL);
+
+			g_string_append_unichar (repl_str, '.');
+			g_string_append (repl_str, old_suffix);
+
+			g_free (old_suffix);
+			g_free (name);
+			g_object_unref (img_file);
+		}
+		else {
+			char *suffix = eom_pixbuf_get_common_suffix (format);
+
+			g_string_append_unichar (repl_str, '.');
+			g_string_append (repl_str, suffix);
+
+			g_free (suffix);
+		}
+
+		filename = repl_str->str;
+	}
+
+	g_string_free (repl_str, FALSE);
+	g_string_free (str, TRUE);
+
+	return filename;
+}
+
+gboolean
+eom_uri_converter_requires_exif (EomURIConverter *converter)
+{
+	g_return_val_if_fail (EOM_IS_URI_CONVERTER (converter), FALSE);
+
+	return converter->priv->requires_exif;
+}
+
+/**
+ * eom_uri_converter_check:
+ * @converter: a #EomURIConverter
+ * @img_list: (element-type GFile): a #Gfile list
+ * @error: a #GError location to store the error occurring, or NULL to ignore
+ */
+
+gboolean
+eom_uri_converter_check (EomURIConverter *converter, GList *img_list, GError **error)
+{
+	GList *it;
+	GList *file_list = NULL;
+	gboolean all_different = TRUE;
+
+	g_return_val_if_fail (EOM_IS_URI_CONVERTER (converter), FALSE);
+
+	/* convert all image uris */
+	for (it = img_list; it != NULL; it = it->next) {
+		gboolean result;
+		GFile *file;
+		GError *conv_error = NULL;
+
+		result = eom_uri_converter_do (converter, EOM_IMAGE (it->data),
+					       &file, NULL, &conv_error);
+
+		if (result) {
+			file_list = g_list_prepend (file_list, file);
+		}
+	}
+
+	/* check for all different uris */
+	for (it = file_list; it != NULL && all_different; it = it->next) {
+		GList *p;
+		GFile *file;
+
+		file = (GFile*) it->data;
+
+		for (p = it->next; p != NULL && all_different; p = p->next) {
+			all_different = !g_file_equal (file, (GFile*) p->data);
+		}
+	}
+
+	if (!all_different) {
+		g_set_error (error, EOM_UC_ERROR,
+			     EOM_UC_ERROR_EQUAL_FILENAMES,
+			     _("At least two file names are equal."));
+	}
+
+        g_list_free (file_list);
+
+	return all_different;
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/22.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/22.html new file mode 100644 index 0000000..f64fc12 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/22.html @@ -0,0 +1,1158 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
/* Eye Of Mate - General Utilities
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <lucasr@gnome.org>
+ *
+ * Based on code by:
+ *	- Jens Finke <jens@gnome.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/time.h>
+#ifdef HAVE_STRPTIME
+#define _XOPEN_SOURCE
+#endif /* HAVE_STRPTIME */
+
+#include <time.h>
+
+#include "eom-util.h"
+
+#include <errno.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+#include <glib/gi18n.h>
+
+void
+eom_util_show_help (const gchar *section, GtkWindow *parent)
+{
+	GError *error = NULL;
+	gchar *uri = NULL;
+
+	if (section)
+		uri = g_strdup_printf ("help:eom/%s", section);
+
+	gtk_show_uri_on_window (parent, ((uri != NULL) ? uri : "help:eom"),
+		      gtk_get_current_event_time (), &error);
+
+	g_free (uri);
+
+	if (error) {
+		GtkWidget *dialog;
+
+		dialog = gtk_message_dialog_new (parent,
+						 0,
+						 GTK_MESSAGE_ERROR,
+						 GTK_BUTTONS_OK,
+						 _("Could not display help for Eye of MATE"));
+
+		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+							  "%s", error->message);
+
+		g_signal_connect_swapped (dialog, "response",
+					  G_CALLBACK (gtk_widget_destroy),
+					  dialog);
+		gtk_widget_show (dialog);
+
+		g_error_free (error);
+	}
+}
+
+gchar *
+eom_util_make_valid_utf8 (const gchar *str)
+{
+	GString *string;
+	const char *remainder, *invalid;
+	int remaining_bytes, valid_bytes;
+
+	string = NULL;
+	remainder = str;
+	remaining_bytes = strlen (str);
+
+	while (remaining_bytes != 0) {
+		if (g_utf8_validate (remainder, remaining_bytes, &invalid)) {
+			break;
+		}
+
+		valid_bytes = invalid - remainder;
+
+		if (string == NULL) {
+			string = g_string_sized_new (remaining_bytes);
+		}
+
+		g_string_append_len (string, remainder, valid_bytes);
+		g_string_append_c (string, '?');
+
+		remaining_bytes -= valid_bytes + 1;
+		remainder = invalid + 1;
+	}
+
+	if (string == NULL) {
+		return g_strdup (str);
+	}
+
+	g_string_append (string, remainder);
+	g_string_append (string, _(" (invalid Unicode)"));
+
+	g_assert (g_utf8_validate (string->str, -1, NULL));
+
+	return g_string_free (string, FALSE);
+}
+
+GSList*
+eom_util_parse_uri_string_list_to_file_list (const gchar *uri_list)
+{
+	GSList* file_list = NULL;
+	gsize i = 0;
+	gchar **uris;
+
+	uris = g_uri_list_extract_uris (uri_list);
+
+	while (uris[i] != NULL) {
+		file_list = g_slist_append (file_list, g_file_new_for_uri (uris[i]));
+		i++;
+	}
+
+	g_strfreev (uris);
+
+	return file_list;
+}
+
+GSList*
+eom_util_string_list_to_file_list (GSList *string_list)
+{
+	GSList *it = NULL;
+	GSList *file_list = NULL;
+
+	for (it = string_list; it != NULL; it = it->next) {
+		char *uri_str;
+
+		uri_str = (gchar *) it->data;
+
+		file_list = g_slist_prepend (file_list,
+					     g_file_new_for_uri (uri_str));
+	}
+
+	return g_slist_reverse (file_list);
+}
+
+GSList*
+eom_util_strings_to_file_list (gchar **strings)
+{
+	int i;
+ 	GSList *file_list = NULL;
+
+	for (i = 0; strings[i]; i++) {
+ 		file_list = g_slist_prepend (file_list,
+					      g_file_new_for_uri (strings[i]));
+ 	}
+
+ 	return g_slist_reverse (file_list);
+}
+
+GSList*
+eom_util_string_array_to_list (const gchar **files, gboolean create_uri)
+{
+	gint i;
+	GSList *list = NULL;
+
+	if (files == NULL) return list;
+
+	for (i = 0; files[i]; i++) {
+		char *str;
+
+		if (create_uri) {
+			GFile *file;
+
+			file = g_file_new_for_commandline_arg (files[i]);
+			str = g_file_get_uri (file);
+
+			g_object_unref (file);
+		} else {
+			str = g_strdup (files[i]);
+		}
+
+		if (str) {
+			list = g_slist_prepend (list, g_strdup (str));
+			g_free (str);
+		}
+	}
+
+	return g_slist_reverse (list);
+}
+
+gchar **
+eom_util_string_array_make_absolute (gchar **files)
+{
+	int i;
+	int size;
+	gchar **abs_files;
+	GFile *file;
+
+	if (files == NULL)
+		return NULL;
+
+	size = g_strv_length (files);
+
+	/* Ensure new list is NULL-terminated */
+	abs_files = g_new0 (gchar *, size+1);
+
+	for (i = 0; i < size; i++) {
+		file = g_file_new_for_commandline_arg (files[i]);
+		abs_files[i] = g_file_get_uri (file);
+
+		g_object_unref (file);
+	}
+
+	return abs_files;
+}
+
+static gchar *dot_dir = NULL;
+
+static gboolean
+ensure_dir_exists (const char *dir)
+{
+	if (g_file_test (dir, G_FILE_TEST_IS_DIR))
+		return TRUE;
+
+	if (g_mkdir_with_parents (dir, 0700) == 0)
+		return TRUE;
+
+	if (errno == EEXIST)
+		return g_file_test (dir, G_FILE_TEST_IS_DIR);
+
+	g_warning ("Failed to create directory %s: %s", dir, strerror (errno));
+	return FALSE;
+}
+
+const gchar *
+eom_util_dot_dir (void)
+{
+	if (dot_dir == NULL) {
+		gboolean exists;
+
+			dot_dir = g_build_filename(g_get_user_config_dir(), "mate", "eom", NULL);
+
+		exists = ensure_dir_exists (dot_dir);
+
+		if (G_UNLIKELY (!exists)) {
+			static gboolean printed_warning = FALSE;
+
+			if (!printed_warning) {
+				g_warning ("EOM could not save some of your preferences in its settings directory due to a file with the same name (%s) blocking its creation. Please remove that file, or move it away.", dot_dir);
+				printed_warning = TRUE;
+			}
+			dot_dir = NULL;
+			return NULL;
+		}
+	}
+
+	return dot_dir;
+}
+
+/* Based on eel_filename_strip_extension() */
+
+/**
+ * eom_util_filename_get_extension:
+ * @filename: a filename
+ *
+ * Returns a reasonably good guess of the file extension of @filename.
+ *
+ * Returns: a newly allocated string with the file extension of @filename.
+ **/
+char *
+eom_util_filename_get_extension (const char * filename)
+{
+	char *begin, *begin2;
+
+	if (filename == NULL) {
+		return NULL;
+	}
+
+	begin = strrchr (filename, '.');
+
+	if (begin && begin != filename) {
+		if (strcmp (begin, ".gz") == 0 ||
+		    strcmp (begin, ".bz2") == 0 ||
+		    strcmp (begin, ".sit") == 0 ||
+		    strcmp (begin, ".Z") == 0) {
+			begin2 = begin - 1;
+			while (begin2 > filename &&
+			       *begin2 != '.') {
+				begin2--;
+			}
+			if (begin2 != filename) {
+				begin = begin2;
+			}
+		}
+		begin ++;
+	} else {
+		return NULL;
+	}
+
+	return g_strdup (begin);
+}
+
+
+/**
+ * eom_util_file_is_persistent:
+ * @file: a #GFile
+ *
+ * Checks whether @file is a non-removable local mount.
+ *
+ * Returns: %TRUE if @file is in a non-removable mount,
+ * %FALSE otherwise or when it is remote.
+ **/
+gboolean
+eom_util_file_is_persistent (GFile *file)
+{
+	GMount *mount;
+
+	if (!g_file_is_native (file))
+		return FALSE;
+
+	mount = g_file_find_enclosing_mount (file, NULL, NULL);
+	if (mount) {
+		if (g_mount_can_unmount (mount)) {
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static void
+_eom_util_show_file_in_filemanager_fallback (GFile *file, GtkWindow *toplevel)
+{
+	gchar *uri = NULL;
+	GError *error = NULL;
+	guint32 timestamp = gtk_get_current_event_time ();
+
+	if (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_DIRECTORY) {
+		uri = g_file_get_uri (file);
+	} else {
+		/* If input file is not a directory we must open it's
+		   folder/parent to avoid opening the file itself     */
+		GFile *parent_file;
+
+		parent_file = g_file_get_parent (file);
+		if (G_LIKELY (parent_file))
+			uri = g_file_get_uri (parent_file);
+		g_object_unref (parent_file);
+	}
+
+	if (uri && !gtk_show_uri_on_window (toplevel, uri, timestamp, &error)) {
+		g_warning ("Couldn't show containing folder \"%s\": %s", uri,
+			   error->message);
+		g_error_free (error);
+	}
+
+	g_free (uri);
+}
+
+void
+eom_util_show_file_in_filemanager (GFile *file, GtkWindow *toplevel)
+{
+	GDBusProxy *proxy;
+	gboolean done = FALSE;
+
+	g_return_if_fail (file != NULL);
+
+	proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+				G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
+				G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+				NULL, "org.freedesktop.FileManager1",
+				"/org/freedesktop/FileManager1",
+				"org.freedesktop.FileManager1",
+				NULL, NULL);
+
+	if (proxy) {
+		gchar *uri = g_file_get_uri (file);
+		gchar *startup_id;
+		GVariant *params, *result;
+		GVariantBuilder builder;
+
+		g_variant_builder_init (&builder,
+					G_VARIANT_TYPE ("as"));
+		g_variant_builder_add (&builder, "s", uri);
+
+		/* This seems to be the expected format, as other values
+		   cause the filemanager window not to get focus. */
+		startup_id = g_strdup_printf("_TIME%u",
+					     gtk_get_current_event_time());
+
+		/* params is floating! */
+		params = g_variant_new ("(ass)", &builder, startup_id);
+
+		g_free (startup_id);
+		g_variant_builder_clear (&builder);
+
+		/* Floating params-GVariant is consumed here */
+		result = g_dbus_proxy_call_sync (proxy, "ShowItems",
+						 params, G_DBUS_CALL_FLAGS_NONE,
+						 -1, NULL, NULL);
+
+		/* Receiving a non-NULL result counts as a successful call. */
+		if (G_LIKELY (result != NULL)) {
+			done = TRUE;
+			g_variant_unref (result);
+		}
+
+		g_free (uri);
+		g_object_unref (proxy);
+	}
+
+	/* Fallback to gtk_show_uri() if launch over DBus is not possible */
+	if (!done)
+		_eom_util_show_file_in_filemanager_fallback (file, toplevel);
+}
+
+gboolean
+eom_notebook_page_scroll_event_cb (GtkWidget         *widget,
+                                   GdkEventScroll    *event)
+
+{
+    GtkNotebook *notebook = GTK_NOTEBOOK (widget);
+    GtkWidget *child, *event_widget, *action_widget;
+
+    child = gtk_notebook_get_nth_page (notebook, gtk_notebook_get_current_page (notebook));
+    if (child == NULL)
+        return FALSE;
+
+    event_widget = gtk_get_event_widget ((GdkEvent*) event);
+
+    /* Ignore scroll events from the content of the page */
+    if (event_widget == NULL || event_widget == child || gtk_widget_is_ancestor (event_widget, child))
+        return FALSE;
+
+    /* And also from the action widgets */
+    action_widget = gtk_notebook_get_action_widget (notebook, GTK_PACK_START);
+    if (event_widget == action_widget || (action_widget != NULL && gtk_widget_is_ancestor (event_widget, action_widget)))
+        return FALSE;
+
+    action_widget = gtk_notebook_get_action_widget (notebook, GTK_PACK_END);
+    if (event_widget == action_widget || (action_widget != NULL && gtk_widget_is_ancestor (event_widget, action_widget)))
+        return FALSE;
+
+    switch (event->direction)
+    {
+        case GDK_SCROLL_RIGHT:
+        case GDK_SCROLL_DOWN:
+            gtk_notebook_next_page (notebook);
+            break;
+        case GDK_SCROLL_LEFT:
+        case GDK_SCROLL_UP:
+            gtk_notebook_prev_page (notebook);
+            break;
+        case GDK_SCROLL_SMOOTH:
+            switch (gtk_notebook_get_tab_pos (notebook))
+            {
+                case GTK_POS_LEFT:
+                case GTK_POS_RIGHT:
+                    if (event->delta_y > 0)
+                    gtk_notebook_next_page (notebook);
+                    else if (event->delta_y < 0)
+                    gtk_notebook_prev_page (notebook);
+                    break;
+                case GTK_POS_TOP:
+                case GTK_POS_BOTTOM:
+                    if (event->delta_x > 0)
+                    gtk_notebook_next_page (notebook);
+                    else if (event->delta_x < 0)
+                    gtk_notebook_prev_page (notebook);
+                    break;
+            }
+            break;
+    }
+
+    return TRUE;
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/23.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/23.html new file mode 100644 index 0000000..ddee409 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/23.html @@ -0,0 +1,11714 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+2145
+2146
+2147
+2148
+2149
+2150
+2151
+2152
+2153
+2154
+2155
+2156
+2157
+2158
+2159
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2180
+2181
+2182
+2183
+2184
+2185
+2186
+2187
+2188
+2189
+2190
+2191
+2192
+2193
+2194
+2195
+2196
+2197
+2198
+2199
+2200
+2201
+2202
+2203
+2204
+2205
+2206
+2207
+2208
+2209
+2210
+2211
+2212
+2213
+2214
+2215
+2216
+2217
+2218
+2219
+2220
+2221
+2222
+2223
+2224
+2225
+2226
+2227
+2228
+2229
+2230
+2231
+2232
+2233
+2234
+2235
+2236
+2237
+2238
+2239
+2240
+2241
+2242
+2243
+2244
+2245
+2246
+2247
+2248
+2249
+2250
+2251
+2252
+2253
+2254
+2255
+2256
+2257
+2258
+2259
+2260
+2261
+2262
+2263
+2264
+2265
+2266
+2267
+2268
+2269
+2270
+2271
+2272
+2273
+2274
+2275
+2276
+2277
+2278
+2279
+2280
+2281
+2282
+2283
+2284
+2285
+2286
+2287
+2288
+2289
+2290
+2291
+2292
+2293
+2294
+2295
+2296
+2297
+2298
+2299
+2300
+2301
+2302
+2303
+2304
+2305
+2306
+2307
+2308
+2309
+2310
+2311
+2312
+2313
+2314
+2315
+2316
+2317
+2318
+2319
+2320
+2321
+2322
+2323
+2324
+2325
+2326
+2327
+2328
+2329
+2330
+2331
+2332
+2333
+2334
+2335
+2336
+2337
+2338
+2339
+2340
+2341
+2342
+2343
+2344
+2345
+2346
+2347
+2348
+2349
+2350
+2351
+2352
+2353
+2354
+2355
+2356
+2357
+2358
+2359
+2360
+2361
+2362
+2363
+2364
+2365
+2366
+2367
+2368
+2369
+2370
+2371
+2372
+2373
+2374
+2375
+2376
+2377
+2378
+2379
+2380
+2381
+2382
+2383
+2384
+2385
+2386
+2387
+2388
+2389
+2390
+2391
+2392
+2393
+2394
+2395
+2396
+2397
+2398
+2399
+2400
+2401
+2402
+2403
+2404
+2405
+2406
+2407
+2408
+2409
+2410
+2411
+2412
+2413
+2414
+2415
+2416
+2417
+2418
+2419
+2420
+2421
+2422
+2423
+2424
+2425
+2426
+2427
+2428
+2429
+2430
+2431
+2432
+2433
+2434
+2435
+2436
+2437
+2438
+2439
+2440
+2441
+2442
+2443
+2444
+2445
+2446
+2447
+2448
+2449
+2450
+2451
+2452
+2453
+2454
+2455
+2456
+2457
+2458
+2459
+2460
+2461
+2462
+2463
+2464
+2465
+2466
+2467
+2468
+2469
+2470
+2471
+2472
+2473
+2474
+2475
+2476
+2477
+2478
+2479
+2480
+2481
+2482
+2483
+2484
+2485
+2486
+2487
+2488
+2489
+2490
+2491
+2492
+2493
+2494
+2495
+2496
+2497
+2498
+2499
+2500
+2501
+2502
+2503
+2504
+2505
+2506
+2507
+2508
+2509
+2510
+2511
+2512
+2513
+2514
+2515
+2516
+2517
+2518
+2519
+2520
+2521
+2522
+2523
+2524
+2525
+2526
+2527
+2528
+2529
+2530
+2531
+2532
+2533
+2534
+2535
+2536
+2537
+2538
+2539
+2540
+2541
+2542
+2543
+2544
+2545
+2546
+2547
+2548
+2549
+2550
+2551
+2552
+2553
+2554
+2555
+2556
+2557
+2558
+2559
+2560
+2561
+2562
+2563
+2564
+2565
+2566
+2567
+2568
+2569
+2570
+2571
+2572
+2573
+2574
+2575
+2576
+2577
+2578
+2579
+2580
+2581
+2582
+2583
+2584
+2585
+2586
+2587
+2588
+2589
+2590
+2591
+2592
+2593
+2594
+2595
+2596
+2597
+2598
+2599
+2600
+2601
+2602
+2603
+2604
+2605
+2606
+2607
+2608
+2609
+2610
+2611
+2612
+2613
+2614
+2615
+2616
+2617
+2618
+2619
+2620
+2621
+2622
+2623
+2624
+2625
+2626
+2627
+2628
+2629
+2630
+2631
+2632
+2633
+2634
+2635
+2636
+2637
+2638
+2639
+2640
+2641
+2642
+2643
+2644
+2645
+2646
+2647
+2648
+2649
+2650
+2651
+2652
+2653
+2654
+2655
+2656
+2657
+2658
+2659
+2660
+2661
+2662
+2663
+2664
+2665
+2666
+2667
+2668
+2669
+2670
+2671
+2672
+2673
+2674
+2675
+2676
+2677
+2678
+2679
+2680
+2681
+2682
+2683
+2684
+2685
+2686
+2687
+2688
+2689
+2690
+2691
+2692
+2693
+2694
+2695
+2696
+2697
+2698
+2699
+2700
+2701
+2702
+2703
+2704
+2705
+2706
+2707
+2708
+2709
+2710
+2711
+2712
+2713
+2714
+2715
+2716
+2717
+2718
+2719
+2720
+2721
+2722
+2723
+2724
+2725
+2726
+2727
+2728
+2729
+2730
+2731
+2732
+2733
+2734
+2735
+2736
+2737
+2738
+2739
+2740
+2741
+2742
+2743
+2744
+2745
+2746
+2747
+2748
+2749
+2750
+2751
+2752
+2753
+2754
+2755
+2756
+2757
+2758
+2759
+2760
+2761
+2762
+2763
+2764
+2765
+2766
+2767
+2768
+2769
+2770
+2771
+2772
+2773
+2774
+2775
+2776
+2777
+2778
+2779
+2780
+2781
+2782
+2783
+2784
+2785
+2786
+2787
+2788
+2789
+2790
+2791
+2792
+2793
+2794
+2795
+2796
+2797
+2798
+2799
+2800
+2801
+2802
+2803
+2804
+2805
+2806
+2807
+2808
+2809
+2810
+2811
+2812
+2813
+2814
+2815
+2816
+2817
+2818
+2819
+2820
+2821
+2822
+2823
+2824
+2825
+2826
+2827
+2828
+2829
+2830
+2831
+2832
+2833
+2834
+2835
+2836
+2837
+2838
+2839
+2840
+2841
+2842
+2843
+2844
+2845
+2846
+2847
+2848
+2849
+2850
+2851
+2852
+2853
+2854
+2855
+2856
+2857
+2858
+2859
+2860
+2861
+2862
+2863
+2864
+2865
+2866
+2867
+2868
+2869
+2870
+2871
+2872
+2873
+2874
+2875
+2876
+2877
+2878
+2879
+2880
+2881
+2882
+2883
+2884
+2885
+2886
+2887
+2888
+2889
+2890
+2891
+2892
+2893
+2894
+2895
+2896
+2897
+2898
+2899
+2900
+2901
+2902
+2903
+2904
+2905
+2906
+2907
+2908
+2909
+2910
+2911
+2912
+2913
+2914
+2915
+2916
+2917
+2918
+2919
+2920
+2921
+2922
+2923
+2924
+2925
+2926
+2927
+2928
+2929
+2930
+2931
+2932
+2933
+2934
+2935
+2936
+2937
+2938
+2939
+2940
+2941
+2942
+2943
+2944
+2945
+2946
+2947
+2948
+2949
+2950
+2951
+2952
+2953
+2954
+2955
+2956
+2957
+2958
+2959
+2960
+2961
+2962
+2963
+2964
+2965
+2966
+2967
+2968
+2969
+2970
+2971
+2972
+2973
+2974
+2975
+2976
+2977
+2978
+2979
+2980
+2981
+2982
+2983
+2984
+2985
+2986
+2987
+2988
+2989
+2990
+2991
+2992
+2993
+2994
+2995
+2996
+2997
+2998
+2999
+3000
+3001
+3002
+3003
+3004
+3005
+3006
+3007
+3008
+3009
+3010
+3011
+3012
+3013
+3014
+3015
+3016
+3017
+3018
+3019
+3020
+3021
+3022
+3023
+3024
+3025
+3026
+3027
+3028
+3029
+3030
+3031
+3032
+3033
+3034
+3035
+3036
+3037
+3038
+3039
+3040
+3041
+3042
+3043
+3044
+3045
+3046
+3047
+3048
+3049
+3050
+3051
+3052
+3053
+3054
+3055
+3056
+3057
+3058
+3059
+3060
+3061
+3062
+3063
+3064
+3065
+3066
+3067
+3068
+3069
+3070
+3071
+3072
+3073
+3074
+3075
+3076
+3077
+3078
+3079
+3080
+3081
+3082
+3083
+3084
+3085
+3086
+3087
+3088
+3089
+3090
+3091
+3092
+3093
+3094
+3095
+3096
+3097
+3098
+3099
+3100
+3101
+3102
+3103
+3104
+3105
+3106
+3107
+3108
+3109
+3110
+3111
+3112
+3113
+3114
+3115
+3116
+3117
+3118
+3119
+3120
+3121
+3122
+3123
+3124
+3125
+3126
+3127
+3128
+3129
+3130
+3131
+3132
+3133
+3134
+3135
+3136
+3137
+3138
+3139
+3140
+3141
+3142
+3143
+3144
+3145
+3146
+3147
+3148
+3149
+3150
+3151
+3152
+3153
+3154
+3155
+3156
+3157
+3158
+3159
+3160
+3161
+3162
+3163
+3164
+3165
+3166
+3167
+3168
+3169
+3170
+3171
+3172
+3173
+3174
+3175
+3176
+3177
+3178
+3179
+3180
+3181
+3182
+3183
+3184
+3185
+3186
+3187
+3188
+3189
+3190
+3191
+3192
+3193
+3194
+3195
+3196
+3197
+3198
+3199
+3200
+3201
+3202
+3203
+3204
+3205
+3206
+3207
+3208
+3209
+3210
+3211
+3212
+3213
+3214
+3215
+3216
+3217
+3218
+3219
+3220
+3221
+3222
+3223
+3224
+3225
+3226
+3227
+3228
+3229
+3230
+3231
+3232
+3233
+3234
+3235
+3236
+3237
+3238
+3239
+3240
+3241
+3242
+3243
+3244
+3245
+3246
+3247
+3248
+3249
+3250
+3251
+3252
+3253
+3254
+3255
+3256
+3257
+3258
+3259
+3260
+3261
+3262
+3263
+3264
+3265
+3266
+3267
+3268
+3269
+3270
+3271
+3272
+3273
+3274
+3275
+3276
+3277
+3278
+3279
+3280
+3281
+3282
+3283
+3284
+3285
+3286
+3287
+3288
+3289
+3290
+3291
+3292
+3293
+3294
+3295
+3296
+3297
+3298
+3299
+3300
+3301
+3302
+3303
+3304
+3305
+3306
+3307
+3308
+3309
+3310
+3311
+3312
+3313
+3314
+3315
+3316
+3317
+3318
+3319
+3320
+3321
+3322
+3323
+3324
+3325
+3326
+3327
+3328
+3329
+3330
+3331
+3332
+3333
+3334
+3335
+3336
+3337
+3338
+3339
+3340
+3341
+3342
+3343
+3344
+3345
+3346
+3347
+3348
+3349
+3350
+3351
+3352
+3353
+3354
+3355
+3356
+3357
+3358
+3359
+3360
+3361
+3362
+3363
+3364
+3365
+3366
+3367
+3368
+3369
+3370
+3371
+3372
+3373
+3374
+3375
+3376
+3377
+3378
+3379
+3380
+3381
+3382
+3383
+3384
+3385
+3386
+3387
+3388
+3389
+3390
+3391
+3392
+3393
+3394
+3395
+3396
+3397
+3398
+3399
+3400
+3401
+3402
+3403
+3404
+3405
+3406
+3407
+3408
+3409
+3410
+3411
+3412
+3413
+3414
+3415
+3416
+3417
+3418
+3419
+3420
+3421
+3422
+3423
+3424
+3425
+3426
+3427
+3428
+3429
+3430
+3431
+3432
+3433
+3434
+3435
+3436
+3437
+3438
+3439
+3440
+3441
+3442
+3443
+3444
+3445
+3446
+3447
+3448
+3449
+3450
+3451
+3452
+3453
+3454
+3455
+3456
+3457
+3458
+3459
+3460
+3461
+3462
+3463
+3464
+3465
+3466
+3467
+3468
+3469
+3470
+3471
+3472
+3473
+3474
+3475
+3476
+3477
+3478
+3479
+3480
+3481
+3482
+3483
+3484
+3485
+3486
+3487
+3488
+3489
+3490
+3491
+3492
+3493
+3494
+3495
+3496
+3497
+3498
+3499
+3500
+3501
+3502
+3503
+3504
+3505
+3506
+3507
+3508
+3509
+3510
+3511
+3512
+3513
+3514
+3515
+3516
+3517
+3518
+3519
+3520
+3521
+3522
+3523
+3524
+3525
+3526
+3527
+3528
+3529
+3530
+3531
+3532
+3533
+3534
+3535
+3536
+3537
+3538
+3539
+3540
+3541
+3542
+3543
+3544
+3545
+3546
+3547
+3548
+3549
+3550
+3551
+3552
+3553
+3554
+3555
+3556
+3557
+3558
+3559
+3560
+3561
+3562
+3563
+3564
+3565
+3566
+3567
+3568
+3569
+3570
+3571
+3572
+3573
+3574
+3575
+3576
+3577
+3578
+3579
+3580
+3581
+3582
+3583
+3584
+3585
+3586
+3587
+3588
+3589
+3590
+3591
+3592
+3593
+3594
+3595
+3596
+3597
+3598
+3599
+3600
+3601
+3602
+3603
+3604
+3605
+3606
+3607
+3608
+3609
+3610
+3611
+3612
+3613
+3614
+3615
+3616
+3617
+3618
+3619
+3620
+3621
+3622
+3623
+3624
+3625
+3626
+3627
+3628
+3629
+3630
+3631
+3632
+3633
+3634
+3635
+3636
+3637
+3638
+3639
+3640
+3641
+3642
+3643
+3644
+3645
+3646
+3647
+3648
+3649
+3650
+3651
+3652
+3653
+3654
+3655
+3656
+3657
+3658
+3659
+3660
+3661
+3662
+3663
+3664
+3665
+3666
+3667
+3668
+3669
+3670
+3671
+3672
+3673
+3674
+3675
+3676
+3677
+3678
+3679
+3680
+3681
+3682
+3683
+3684
+3685
+3686
+3687
+3688
+3689
+3690
+3691
+3692
+3693
+3694
+3695
+3696
+3697
+3698
+3699
+3700
+3701
+3702
+3703
+3704
+3705
+3706
+3707
+3708
+3709
+3710
+3711
+3712
+3713
+3714
+3715
+3716
+3717
+3718
+3719
+3720
+3721
+3722
+3723
+3724
+3725
+3726
+3727
+3728
+3729
+3730
+3731
+3732
+3733
+3734
+3735
+3736
+3737
+3738
+3739
+3740
+3741
+3742
+3743
+3744
+3745
+3746
+3747
+3748
+3749
+3750
+3751
+3752
+3753
+3754
+3755
+3756
+3757
+3758
+3759
+3760
+3761
+3762
+3763
+3764
+3765
+3766
+3767
+3768
+3769
+3770
+3771
+3772
+3773
+3774
+3775
+3776
+3777
+3778
+3779
+3780
+3781
+3782
+3783
+3784
+3785
+3786
+3787
+3788
+3789
+3790
+3791
+3792
+3793
+3794
+3795
+3796
+3797
+3798
+3799
+3800
+3801
+3802
+3803
+3804
+3805
+3806
+3807
+3808
+3809
+3810
+3811
+3812
+3813
+3814
+3815
+3816
+3817
+3818
+3819
+3820
+3821
+3822
+3823
+3824
+3825
+3826
+3827
+3828
+3829
+3830
+3831
+3832
+3833
+3834
+3835
+3836
+3837
+3838
+3839
+3840
+3841
+3842
+3843
+3844
+3845
+3846
+3847
+3848
+3849
+3850
+3851
+3852
+3853
+3854
+3855
+3856
+3857
+3858
+3859
+3860
+3861
+3862
+3863
+3864
+3865
+3866
+3867
+3868
+3869
+3870
+3871
+3872
+3873
+3874
+3875
+3876
+3877
+3878
+3879
+3880
+3881
+3882
+3883
+3884
+3885
+3886
+3887
+3888
+3889
+3890
+3891
+3892
+3893
+3894
+3895
+3896
+3897
+3898
+3899
+3900
+3901
+3902
+3903
+3904
+3905
+3906
+3907
+3908
+3909
+3910
+3911
+3912
+3913
+3914
+3915
+3916
+3917
+3918
+3919
+3920
+3921
+3922
+3923
+3924
+3925
+3926
+3927
+3928
+3929
+3930
+3931
+3932
+3933
+3934
+3935
+3936
+3937
+3938
+3939
+3940
+3941
+3942
+3943
+3944
+3945
+3946
+3947
+3948
+3949
+3950
+3951
+3952
+3953
+3954
+3955
+3956
+3957
+3958
+3959
+3960
+3961
+3962
+3963
+3964
+3965
+3966
+3967
+3968
+3969
+3970
+3971
+3972
+3973
+3974
+3975
+3976
+3977
+3978
+3979
+3980
+3981
+3982
+3983
+3984
+3985
+3986
+3987
+3988
+3989
+3990
+3991
+3992
+3993
+3994
+3995
+3996
+3997
+3998
+3999
+4000
+4001
+4002
+4003
+4004
+4005
+4006
+4007
+4008
+4009
+4010
+4011
+4012
+4013
+4014
+4015
+4016
+4017
+4018
+4019
+4020
+4021
+4022
+4023
+4024
+4025
+4026
+4027
+4028
+4029
+4030
+4031
+4032
+4033
+4034
+4035
+4036
+4037
+4038
+4039
+4040
+4041
+4042
+4043
+4044
+4045
+4046
+4047
+4048
+4049
+4050
+4051
+4052
+4053
+4054
+4055
+4056
+4057
+4058
+4059
+4060
+4061
+4062
+4063
+4064
+4065
+4066
+4067
+4068
+4069
+4070
+4071
+4072
+4073
+4074
+4075
+4076
+4077
+4078
+4079
+4080
+4081
+4082
+4083
+4084
+4085
+4086
+4087
+4088
+4089
+4090
+4091
+4092
+4093
+4094
+4095
+4096
+4097
+4098
+4099
+4100
+4101
+4102
+4103
+4104
+4105
+4106
+4107
+4108
+4109
+4110
+4111
+4112
+4113
+4114
+4115
+4116
+4117
+4118
+4119
+4120
+4121
+4122
+4123
+4124
+4125
+4126
+4127
+4128
+4129
+4130
+4131
+4132
+4133
+4134
+4135
+4136
+4137
+4138
+4139
+4140
+4141
+4142
+4143
+4144
+4145
+4146
+4147
+4148
+4149
+4150
+4151
+4152
+4153
+4154
+4155
+4156
+4157
+4158
+4159
+4160
+4161
+4162
+4163
+4164
+4165
+4166
+4167
+4168
+4169
+4170
+4171
+4172
+4173
+4174
+4175
+4176
+4177
+4178
+4179
+4180
+4181
+4182
+4183
+4184
+4185
+4186
+4187
+4188
+4189
+4190
+4191
+4192
+4193
+4194
+4195
+4196
+4197
+4198
+4199
+4200
+4201
+4202
+4203
+4204
+4205
+4206
+4207
+4208
+4209
+4210
+4211
+4212
+4213
+4214
+4215
+4216
+4217
+4218
+4219
+4220
+4221
+4222
+4223
+4224
+4225
+4226
+4227
+4228
+4229
+4230
+4231
+4232
+4233
+4234
+4235
+4236
+4237
+4238
+4239
+4240
+4241
+4242
+4243
+4244
+4245
+4246
+4247
+4248
+4249
+4250
+4251
+4252
+4253
+4254
+4255
+4256
+4257
+4258
+4259
+4260
+4261
+4262
+4263
+4264
+4265
+4266
+4267
+4268
+4269
+4270
+4271
+4272
+4273
+4274
+4275
+4276
+4277
+4278
+4279
+4280
+4281
+4282
+4283
+4284
+4285
+4286
+4287
+4288
+4289
+4290
+4291
+4292
+4293
+4294
+4295
+4296
+4297
+4298
+4299
+4300
+4301
+4302
+4303
+4304
+4305
+4306
+4307
+4308
+4309
+4310
+4311
+4312
+4313
+4314
+4315
+4316
+4317
+4318
+4319
+4320
+4321
+4322
+4323
+4324
+4325
+4326
+4327
+4328
+4329
+4330
+4331
+4332
+4333
+4334
+4335
+4336
+4337
+4338
+4339
+4340
+4341
+4342
+4343
+4344
+4345
+4346
+4347
+4348
+4349
+4350
+4351
+4352
+4353
+4354
+4355
+4356
+4357
+4358
+4359
+4360
+4361
+4362
+4363
+4364
+4365
+4366
+4367
+4368
+4369
+4370
+4371
+4372
+4373
+4374
+4375
+4376
+4377
+4378
+4379
+4380
+4381
+4382
+4383
+4384
+4385
+4386
+4387
+4388
+4389
+4390
+4391
+4392
+4393
+4394
+4395
+4396
+4397
+4398
+4399
+4400
+4401
+4402
+4403
+4404
+4405
+4406
+4407
+4408
+4409
+4410
+4411
+4412
+4413
+4414
+4415
+4416
+4417
+4418
+4419
+4420
+4421
+4422
+4423
+4424
+4425
+4426
+4427
+4428
+4429
+4430
+4431
+4432
+4433
+4434
+4435
+4436
+4437
+4438
+4439
+4440
+4441
+4442
+4443
+4444
+4445
+4446
+4447
+4448
+4449
+4450
+4451
+4452
+4453
+4454
+4455
+4456
+4457
+4458
+4459
+4460
+4461
+4462
+4463
+4464
+4465
+4466
+4467
+4468
+4469
+4470
+4471
+4472
+4473
+4474
+4475
+4476
+4477
+4478
+4479
+4480
+4481
+4482
+4483
+4484
+4485
+4486
+4487
+4488
+4489
+4490
+4491
+4492
+4493
+4494
+4495
+4496
+4497
+4498
+4499
+4500
+4501
+4502
+4503
+4504
+4505
+4506
+4507
+4508
+4509
+4510
+4511
+4512
+4513
+4514
+4515
+4516
+4517
+4518
+4519
+4520
+4521
+4522
+4523
+4524
+4525
+4526
+4527
+4528
+4529
+4530
+4531
+4532
+4533
+4534
+4535
+4536
+4537
+4538
+4539
+4540
+4541
+4542
+4543
+4544
+4545
+4546
+4547
+4548
+4549
+4550
+4551
+4552
+4553
+4554
+4555
+4556
+4557
+4558
+4559
+4560
+4561
+4562
+4563
+4564
+4565
+4566
+4567
+4568
+4569
+4570
+4571
+4572
+4573
+4574
+4575
+4576
+4577
+4578
+4579
+4580
+4581
+4582
+4583
+4584
+4585
+4586
+4587
+4588
+4589
+4590
+4591
+4592
+4593
+4594
+4595
+4596
+4597
+4598
+4599
+4600
+4601
+4602
+4603
+4604
+4605
+4606
+4607
+4608
+4609
+4610
+4611
+4612
+4613
+4614
+4615
+4616
+4617
+4618
+4619
+4620
+4621
+4622
+4623
+4624
+4625
+4626
+4627
+4628
+4629
+4630
+4631
+4632
+4633
+4634
+4635
+4636
+4637
+4638
+4639
+4640
+4641
+4642
+4643
+4644
+4645
+4646
+4647
+4648
+4649
+4650
+4651
+4652
+4653
+4654
+4655
+4656
+4657
+4658
+4659
+4660
+4661
+4662
+4663
+4664
+4665
+4666
+4667
+4668
+4669
+4670
+4671
+4672
+4673
+4674
+4675
+4676
+4677
+4678
+4679
+4680
+4681
+4682
+4683
+4684
+4685
+4686
+4687
+4688
+4689
+4690
+4691
+4692
+4693
+4694
+4695
+4696
+4697
+4698
+4699
+4700
+4701
+4702
+4703
+4704
+4705
+4706
+4707
+4708
+4709
+4710
+4711
+4712
+4713
+4714
+4715
+4716
+4717
+4718
+4719
+4720
+4721
+4722
+4723
+4724
+4725
+4726
+4727
+4728
+4729
+4730
+4731
+4732
+4733
+4734
+4735
+4736
+4737
+4738
+4739
+4740
+4741
+4742
+4743
+4744
+4745
+4746
+4747
+4748
+4749
+4750
+4751
+4752
+4753
+4754
+4755
+4756
+4757
+4758
+4759
+4760
+4761
+4762
+4763
+4764
+4765
+4766
+4767
+4768
+4769
+4770
+4771
+4772
+4773
+4774
+4775
+4776
+4777
+4778
+4779
+4780
+4781
+4782
+4783
+4784
+4785
+4786
+4787
+4788
+4789
+4790
+4791
+4792
+4793
+4794
+4795
+4796
+4797
+4798
+4799
+4800
+4801
+4802
+4803
+4804
+4805
+4806
+4807
+4808
+4809
+4810
+4811
+4812
+4813
+4814
+4815
+4816
+4817
+4818
+4819
+4820
+4821
+4822
+4823
+4824
+4825
+4826
+4827
+4828
+4829
+4830
+4831
+4832
+4833
+4834
+4835
+4836
+4837
+4838
+4839
+4840
+4841
+4842
+4843
+4844
+4845
+4846
+4847
+4848
+4849
+4850
+4851
+4852
+4853
+4854
+4855
+4856
+4857
+4858
+4859
+4860
+4861
+4862
+4863
+4864
+4865
+4866
+4867
+4868
+4869
+4870
+4871
+4872
+4873
+4874
+4875
+4876
+4877
+4878
+4879
+4880
+4881
+4882
+4883
+4884
+4885
+4886
+4887
+4888
+4889
+4890
+4891
+4892
+4893
+4894
+4895
+4896
+4897
+4898
+4899
+4900
+4901
+4902
+4903
+4904
+4905
+4906
+4907
+4908
+4909
+4910
+4911
+4912
+4913
+4914
+4915
+4916
+4917
+4918
+4919
+4920
+4921
+4922
+4923
+4924
+4925
+4926
+4927
+4928
+4929
+4930
+4931
+4932
+4933
+4934
+4935
+4936
+4937
+4938
+4939
+4940
+4941
+4942
+4943
+4944
+4945
+4946
+4947
+4948
+4949
+4950
+4951
+4952
+4953
+4954
+4955
+4956
+4957
+4958
+4959
+4960
+4961
+4962
+4963
+4964
+4965
+4966
+4967
+4968
+4969
+4970
+4971
+4972
+4973
+4974
+4975
+4976
+4977
+4978
+4979
+4980
+4981
+4982
+4983
+4984
+4985
+4986
+4987
+4988
+4989
+4990
+4991
+4992
+4993
+4994
+4995
+4996
+4997
+4998
+4999
+5000
+5001
+5002
+5003
+5004
+5005
+5006
+5007
+5008
+5009
+5010
+5011
+5012
+5013
+5014
+5015
+5016
+5017
+5018
+5019
+5020
+5021
+5022
+5023
+5024
+5025
+5026
+5027
+5028
+5029
+5030
+5031
+5032
+5033
+5034
+5035
+5036
+5037
+5038
+5039
+5040
+5041
+5042
+5043
+5044
+5045
+5046
+5047
+5048
+5049
+5050
+5051
+5052
+5053
+5054
+5055
+5056
+5057
+5058
+5059
+5060
+5061
+5062
+5063
+5064
+5065
+5066
+5067
+5068
+5069
+5070
+5071
+5072
+5073
+5074
+5075
+5076
+5077
+5078
+5079
+5080
+5081
+5082
+5083
+5084
+5085
+5086
+5087
+5088
+5089
+5090
+5091
+5092
+5093
+5094
+5095
+5096
+5097
+5098
+5099
+5100
+5101
+5102
+5103
+5104
+5105
+5106
+5107
+5108
+5109
+5110
+5111
+5112
+5113
+5114
+5115
+5116
+5117
+5118
+5119
+5120
+5121
+5122
+5123
+5124
+5125
+5126
+5127
+5128
+5129
+5130
+5131
+5132
+5133
+5134
+5135
+5136
+5137
+5138
+5139
+5140
+5141
+5142
+5143
+5144
+5145
+5146
+5147
+5148
+5149
+5150
+5151
+5152
+5153
+5154
+5155
+5156
+5157
+5158
+5159
+5160
+5161
+5162
+5163
+5164
+5165
+5166
+5167
+5168
+5169
+5170
+5171
+5172
+5173
+5174
+5175
+5176
+5177
+5178
+5179
+5180
+5181
+5182
+5183
+5184
+5185
+5186
+5187
+5188
+5189
+5190
+5191
+5192
+5193
+5194
+5195
+5196
+5197
+5198
+5199
+5200
+5201
+5202
+5203
+5204
+5205
+5206
+5207
+5208
+5209
+5210
+5211
+5212
+5213
+5214
+5215
+5216
+5217
+5218
+5219
+5220
+5221
+5222
+5223
+5224
+5225
+5226
+5227
+5228
+5229
+5230
+5231
+5232
+5233
+5234
+5235
+5236
+5237
+5238
+5239
+5240
+5241
+5242
+5243
+5244
+5245
+5246
+5247
+5248
+5249
+5250
+5251
+5252
+5253
+5254
+5255
+5256
+5257
+5258
+5259
+5260
+5261
+5262
+5263
+5264
+5265
+5266
+5267
+5268
+5269
+5270
+5271
+5272
+5273
+5274
+5275
+5276
+5277
+5278
+5279
+5280
+5281
+5282
+5283
+5284
+5285
+5286
+5287
+5288
+5289
+5290
+5291
+5292
+5293
+5294
+5295
+5296
+5297
+5298
+5299
+5300
+5301
+5302
+5303
+5304
+5305
+5306
+5307
+5308
+5309
+5310
+5311
+5312
+5313
+5314
+5315
+5316
+5317
+5318
+5319
+5320
+5321
+5322
+5323
+5324
+5325
+5326
+5327
+5328
+5329
+5330
+5331
+5332
+5333
+5334
+5335
+5336
+5337
+5338
+5339
+5340
+5341
+5342
+5343
+5344
+5345
+5346
+5347
+5348
+5349
+5350
+5351
+5352
+5353
+5354
+5355
+5356
+5357
+5358
+5359
+5360
+5361
+5362
+5363
+5364
+5365
+5366
+5367
+5368
+5369
+5370
+5371
+5372
+5373
+5374
+5375
+5376
+5377
+5378
+5379
+5380
+5381
+5382
+5383
+5384
+5385
+5386
+5387
+5388
+5389
+5390
+5391
+5392
+5393
+5394
+5395
+5396
+5397
+5398
+5399
+5400
+5401
+5402
+5403
+5404
+5405
+5406
+5407
+5408
+5409
+5410
+5411
+5412
+5413
+5414
+5415
+5416
+5417
+5418
+5419
+5420
+5421
+5422
+5423
+5424
+5425
+5426
+5427
+5428
+5429
+5430
+5431
+5432
+5433
+5434
+5435
+5436
+5437
+5438
+5439
+5440
+5441
+5442
+5443
+5444
+5445
+5446
+5447
+5448
+5449
+5450
+5451
+5452
+5453
+5454
+5455
+5456
+5457
+5458
+5459
+5460
+5461
+5462
+5463
+5464
+5465
+5466
+5467
+5468
+5469
+5470
+5471
+5472
+5473
+5474
+5475
+5476
+5477
+5478
+5479
+5480
+5481
+5482
+5483
+5484
+5485
+5486
+5487
+5488
+5489
+5490
+5491
+5492
+5493
+5494
+5495
+5496
+5497
+5498
+5499
+5500
+5501
+5502
+5503
+5504
+5505
+5506
+5507
+5508
+5509
+5510
+5511
+5512
+5513
+5514
+5515
+5516
+5517
+5518
+5519
+5520
+5521
+5522
+5523
+5524
+5525
+5526
+5527
+5528
+5529
+5530
+5531
+5532
+5533
+5534
+5535
+5536
+5537
+5538
+5539
+5540
+5541
+5542
+5543
+5544
+5545
+5546
+5547
+5548
+5549
+5550
+5551
+5552
+5553
+5554
+5555
+5556
+5557
+5558
+5559
+5560
+5561
+5562
+5563
+5564
+5565
+5566
+5567
+5568
+5569
+5570
+5571
+5572
+5573
+5574
+5575
+5576
+5577
+5578
+5579
+5580
+5581
+5582
+5583
+5584
+5585
+5586
+5587
+5588
+5589
+5590
+5591
+5592
+5593
+5594
+5595
+5596
+5597
+5598
+5599
+5600
+5601
+5602
+5603
+5604
+5605
+5606
+5607
+5608
+5609
+5610
+5611
+5612
+5613
+5614
+5615
+5616
+5617
+5618
+5619
+5620
+5621
+5622
+5623
+5624
+5625
+5626
+5627
+5628
+5629
+5630
+5631
+5632
+5633
+5634
+5635
+5636
+5637
+5638
+5639
+5640
+5641
+5642
+5643
+5644
+5645
+5646
+5647
+5648
+5649
+5650
+5651
+5652
+5653
+5654
+5655
+5656
+5657
+5658
+5659
+5660
+5661
+5662
+5663
+5664
+5665
+5666
+5667
+5668
+5669
+5670
+5671
+5672
+5673
+5674
+5675
+5676
+5677
+5678
+5679
+5680
+5681
+5682
+5683
+5684
+5685
+5686
+5687
+5688
+5689
+5690
+5691
+5692
+5693
+5694
+5695
+5696
+5697
+5698
+5699
+5700
+5701
+5702
+5703
+5704
+5705
+5706
+5707
+5708
/* Eye Of Mate - Main Window
+ *
+ * Copyright (C) 2000-2008 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <lucasr@gnome.org>
+ *
+ * Based on code by:
+ * 	- Federico Mena-Quintero <federico@gnu.org>
+ *	- Jens Finke <jens@gnome.org>
+ * Based on evince code (shell/ev-window.c) by:
+ * 	- Martin Kretzschmar <martink@gnome.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+
+#include "eom-window.h"
+#include "eom-scroll-view.h"
+#include "eom-debug.h"
+#include "eom-file-chooser.h"
+#include "eom-thumb-view.h"
+#include "eom-list-store.h"
+#include "eom-sidebar.h"
+#include "eom-statusbar.h"
+#include "eom-preferences-dialog.h"
+#include "eom-properties-dialog.h"
+#include "eom-print.h"
+#include "eom-error-message-area.h"
+#include "eom-application.h"
+#include "eom-application-internal.h"
+#include "eom-thumb-nav.h"
+#include "eom-config-keys.h"
+#include "eom-job-queue.h"
+#include "eom-jobs.h"
+#include "eom-util.h"
+#include "eom-save-as-dialog-helper.h"
+#include "eom-close-confirmation-dialog.h"
+#include "eom-clipboard-handler.h"
+#include "eom-window-activatable.h"
+#include "eom-metadata-sidebar.h"
+
+#include "eom-enum-types.h"
+
+#include "egg-toolbar-editor.h"
+#include "egg-editable-toolbar.h"
+#include "egg-toolbars-model.h"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gdk/gdkkeysyms.h>
+#include <gio/gdesktopappinfo.h>
+#include <gtk/gtk.h>
+
+#include <libpeas/peas-extension-set.h>
+#include <libpeas/peas-activatable.h>
+
+#if HAVE_LCMS
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#endif
+#include <lcms2.h>
+#endif
+
+#define MATE_DESKTOP_USE_UNSTABLE_API
+#include <libmate-desktop/mate-desktop-utils.h>
+
+#define EOM_WINDOW_MIN_WIDTH  440
+#define EOM_WINDOW_MIN_HEIGHT 350
+
+#define EOM_WINDOW_DEFAULT_WIDTH  540
+#define EOM_WINDOW_DEFAULT_HEIGHT 450
+
+#define EOM_WINDOW_FULLSCREEN_TIMEOUT 5 * 1000
+#define EOM_WINDOW_FULLSCREEN_POPUP_THRESHOLD 5
+
+#define EOM_RECENT_FILES_GROUP  "Graphics"
+#define EOM_RECENT_FILES_APP_NAME "Eye of MATE Image Viewer"
+#define EOM_RECENT_FILES_LIMIT  5
+
+#define EOM_WALLPAPER_FILENAME "eom-wallpaper"
+
+#define is_rtl (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
+
+typedef enum {
+	EOM_WINDOW_STATUS_UNKNOWN,
+	EOM_WINDOW_STATUS_INIT,
+	EOM_WINDOW_STATUS_NORMAL
+} EomWindowStatus;
+
+enum {
+	PROP_0,
+	PROP_COLLECTION_POS,
+	PROP_COLLECTION_RESIZABLE,
+	PROP_STARTUP_FLAGS
+};
+
+enum {
+	SIGNAL_PREPARED,
+	SIGNAL_LAST
+};
+
+static guint signals[SIGNAL_LAST] = { 0 };
+
+struct _EomWindowPrivate {
+	GSettings           *view_settings;
+	GSettings           *ui_settings;
+	GSettings           *fullscreen_settings;
+	GSettings           *lockdown_settings;
+
+	EomListStore        *store;
+	EomImage            *image;
+	EomWindowMode        mode;
+	EomWindowStatus      status;
+
+	GtkUIManager        *ui_mgr;
+	GtkWidget           *box;
+	GtkWidget           *layout;
+	GtkWidget           *cbox;
+	GtkWidget           *view;
+	GtkWidget           *sidebar;
+	GtkWidget           *thumbview;
+	GtkWidget           *statusbar;
+	GtkWidget           *nav;
+	GtkWidget           *message_area;
+	GtkWidget           *toolbar;
+	GtkWidget           *properties_dlg;
+
+	GtkActionGroup      *actions_window;
+	GtkActionGroup      *actions_image;
+	GtkActionGroup      *actions_collection;
+	GtkActionGroup      *actions_recent;
+
+	GtkWidget           *fullscreen_popup;
+	GSource             *fullscreen_timeout_source;
+
+	gboolean             slideshow_random;
+	gboolean             slideshow_loop;
+	gint                 slideshow_switch_timeout;
+	GSource             *slideshow_switch_source;
+
+	guint                fullscreen_idle_inhibit_cookie;
+
+	guint                recent_menu_id;
+
+	EomJob              *load_job;
+	EomJob              *transform_job;
+	EomJob              *save_job;
+	GFile               *last_save_as_folder;
+	EomJob              *copy_job;
+
+	guint                image_info_message_cid;
+	guint                tip_message_cid;
+	guint                copy_file_cid;
+
+	EomStartupFlags      flags;
+	GSList              *file_list;
+
+	EomWindowCollectionPos collection_position;
+	gboolean             collection_resizable;
+
+	GtkActionGroup      *actions_open_with;
+	guint                open_with_menu_id;
+
+	gboolean             save_disabled;
+	gboolean             needs_reload_confirmation;
+
+	GtkPageSetup        *page_setup;
+
+	PeasExtensionSet    *extensions;
+
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+	cmsHPROFILE         *display_profile;
+#endif
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomWindow, eom_window, GTK_TYPE_APPLICATION_WINDOW);
+
+static void eom_window_cmd_fullscreen (GtkAction *action, gpointer user_data);
+static void eom_window_run_fullscreen (EomWindow *window, gboolean slideshow);
+static void eom_window_cmd_slideshow (GtkAction *action, gpointer user_data);
+static void eom_window_cmd_pause_slideshow (GtkAction *action, gpointer user_data);
+static void eom_window_stop_fullscreen (EomWindow *window, gboolean slideshow);
+static void eom_job_load_cb (EomJobLoad *job, gpointer data);
+static void eom_job_save_progress_cb (EomJobSave *job, float progress, gpointer data);
+static void eom_job_progress_cb (EomJobLoad *job, float progress, gpointer data);
+static void eom_job_transform_cb (EomJobTransform *job, gpointer data);
+static void fullscreen_set_timeout (EomWindow *window);
+static void fullscreen_clear_timeout (EomWindow *window);
+static void update_action_groups_state (EomWindow *window);
+static void open_with_launch_application_cb (GtkAction *action, gpointer callback_data);
+static void eom_window_update_openwith_menu (EomWindow *window, EomImage *image);
+static void eom_window_list_store_image_added (GtkTreeModel *tree_model,
+					       GtkTreePath  *path,
+					       GtkTreeIter  *iter,
+					       gpointer      user_data);
+static void eom_window_list_store_image_removed (GtkTreeModel *tree_model,
+                 				 GtkTreePath  *path,
+						 gpointer      user_data);
+static void eom_window_set_wallpaper (EomWindow *window, const gchar *filename, const gchar *visible_filename);
+static gboolean eom_window_save_images (EomWindow *window, GList *images);
+static void disconnect_proxy_cb (GtkUIManager *manager,
+                                 GtkAction *action,
+                                 GtkWidget *proxy,
+                                 EomWindow *window);
+static void eom_window_finish_saving (EomWindow *window);
+static GAppInfo *get_appinfo_for_editor (EomWindow *window);
+
+static GQuark
+eom_window_error_quark (void)
+{
+	static GQuark q = 0;
+
+	if (q == 0)
+		q = g_quark_from_static_string ("eom-window-error-quark");
+
+	return q;
+}
+
+static void
+eom_window_set_collection_mode (EomWindow *window, EomWindowCollectionPos position, gboolean resizable)
+{
+	EomWindowPrivate *priv;
+	GtkWidget *hpaned;
+	EomThumbNavMode mode = EOM_THUMB_NAV_MODE_ONE_ROW;
+
+	eom_debug (DEBUG_PREFERENCES);
+
+	g_return_if_fail (EOM_IS_WINDOW (window));
+
+	priv = window->priv;
+
+	if (priv->collection_position == position &&
+	    priv->collection_resizable == resizable)
+		return;
+
+	priv->collection_position = position;
+	priv->collection_resizable = resizable;
+
+	hpaned = gtk_widget_get_parent (priv->sidebar);
+
+	g_object_ref (hpaned);
+	g_object_ref (priv->nav);
+
+	gtk_container_remove (GTK_CONTAINER (priv->layout), hpaned);
+	gtk_container_remove (GTK_CONTAINER (priv->layout), priv->nav);
+
+	gtk_widget_destroy (priv->layout);
+
+	switch (position) {
+	case EOM_WINDOW_COLLECTION_POS_BOTTOM:
+	case EOM_WINDOW_COLLECTION_POS_TOP:
+		if (resizable) {
+			mode = EOM_THUMB_NAV_MODE_MULTIPLE_ROWS;
+
+			priv->layout = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
+
+			if (position == EOM_WINDOW_COLLECTION_POS_BOTTOM) {
+				gtk_paned_pack1 (GTK_PANED (priv->layout), hpaned, TRUE, FALSE);
+				gtk_paned_pack2 (GTK_PANED (priv->layout), priv->nav, FALSE, TRUE);
+			} else {
+				gtk_paned_pack1 (GTK_PANED (priv->layout), priv->nav, FALSE, TRUE);
+				gtk_paned_pack2 (GTK_PANED (priv->layout), hpaned, TRUE, FALSE);
+			}
+		} else {
+			mode = EOM_THUMB_NAV_MODE_ONE_ROW;
+
+			priv->layout = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+
+			if (position == EOM_WINDOW_COLLECTION_POS_BOTTOM) {
+				gtk_box_pack_start (GTK_BOX (priv->layout), hpaned, TRUE, TRUE, 0);
+				gtk_box_pack_start (GTK_BOX (priv->layout), priv->nav, FALSE, FALSE, 0);
+			} else {
+				gtk_box_pack_start (GTK_BOX (priv->layout), priv->nav, FALSE, FALSE, 0);
+				gtk_box_pack_start (GTK_BOX (priv->layout), hpaned, TRUE, TRUE, 0);
+			}
+		}
+		break;
+
+	case EOM_WINDOW_COLLECTION_POS_LEFT:
+	case EOM_WINDOW_COLLECTION_POS_RIGHT:
+		if (resizable) {
+			mode = EOM_THUMB_NAV_MODE_MULTIPLE_COLUMNS;
+
+			priv->layout = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
+
+			if (position == EOM_WINDOW_COLLECTION_POS_LEFT) {
+				gtk_paned_pack1 (GTK_PANED (priv->layout), priv->nav, FALSE, TRUE);
+				gtk_paned_pack2 (GTK_PANED (priv->layout), hpaned, TRUE, FALSE);
+			} else {
+				gtk_paned_pack1 (GTK_PANED (priv->layout), hpaned, TRUE, FALSE);
+				gtk_paned_pack2 (GTK_PANED (priv->layout), priv->nav, FALSE, TRUE);
+			}
+		} else {
+			mode = EOM_THUMB_NAV_MODE_ONE_COLUMN;
+
+			priv->layout = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
+
+			if (position == EOM_WINDOW_COLLECTION_POS_LEFT) {
+				gtk_box_pack_start (GTK_BOX (priv->layout), priv->nav, FALSE, FALSE, 0);
+				gtk_box_pack_start (GTK_BOX (priv->layout), hpaned, TRUE, TRUE, 0);
+			} else {
+				gtk_box_pack_start (GTK_BOX (priv->layout), hpaned, TRUE, TRUE, 0);
+				gtk_box_pack_start (GTK_BOX (priv->layout), priv->nav, FALSE, FALSE, 0);
+			}
+		}
+
+		break;
+	}
+
+	gtk_box_pack_end (GTK_BOX (priv->cbox), priv->layout, TRUE, TRUE, 0);
+
+	eom_thumb_nav_set_mode (EOM_THUMB_NAV (priv->nav), mode);
+
+	if (priv->mode != EOM_WINDOW_MODE_UNKNOWN) {
+		update_action_groups_state (window);
+	}
+}
+
+static void
+eom_window_can_save_changed_cb (GSettings *settings, gchar *key, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+	EomWindow *window;
+	gboolean save_disabled = FALSE;
+	GtkAction *action_save, *action_save_as;
+
+	eom_debug (DEBUG_PREFERENCES);
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+	priv = EOM_WINDOW (user_data)->priv;
+
+	save_disabled = g_settings_get_boolean (settings, key);
+
+	priv->save_disabled = save_disabled;
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action_save =
+		gtk_action_group_get_action (priv->actions_image, "ImageSave");
+	action_save_as =
+		gtk_action_group_get_action (priv->actions_image, "ImageSaveAs");
+
+	if (priv->save_disabled) {
+		gtk_action_set_sensitive (action_save, FALSE);
+		gtk_action_set_sensitive (action_save_as, FALSE);
+	} else {
+		EomImage *image = eom_window_get_image (window);
+
+		if (EOM_IS_IMAGE (image)) {
+			gtk_action_set_sensitive (action_save,
+						  eom_image_is_modified (image));
+
+			gtk_action_set_sensitive (action_save_as, TRUE);
+		}
+	}
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+static cmsHPROFILE *
+eom_window_get_display_profile (GdkScreen *screen)
+{
+	Display *dpy;
+	Atom icc_atom, type;
+	int format;
+	gulong nitems;
+	gulong bytes_after;
+	gulong length;
+	guchar *str;
+	int result;
+	cmsHPROFILE *profile = NULL;
+	char *atom_name;
+
+	if (!GDK_IS_X11_SCREEN (screen)) {
+		return NULL;
+	}
+
+	dpy = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
+
+	if (gdk_x11_screen_get_screen_number (screen) > 0)
+		atom_name = g_strdup_printf ("_ICC_PROFILE_%d", gdk_x11_screen_get_screen_number (screen));
+	else
+		atom_name = g_strdup ("_ICC_PROFILE");
+
+	icc_atom = gdk_x11_get_xatom_by_name_for_display (gdk_screen_get_display (screen), atom_name);
+
+	g_free (atom_name);
+
+	result = XGetWindowProperty (dpy,
+				     GDK_WINDOW_XID (gdk_screen_get_root_window (screen)),
+				     icc_atom,
+				     0,
+				     G_MAXLONG,
+				     False,
+				     XA_CARDINAL,
+				     &type,
+				     &format,
+				     &nitems,
+				     &bytes_after,
+                                     (guchar **)&str);
+
+	/* TODO: handle bytes_after != 0 */
+
+	if ((result == Success) && (type == XA_CARDINAL) && (nitems > 0)) {
+		switch (format)
+		{
+			case 8:
+				length = nitems;
+				break;
+			case 16:
+				length = sizeof(short) * nitems;
+				break;
+			case 32:
+				length = sizeof(long) * nitems;
+				break;
+			default:
+				eom_debug_message (DEBUG_LCMS, "Unable to read profile, not correcting");
+
+				XFree (str);
+				return NULL;
+		}
+
+		profile = cmsOpenProfileFromMem (str, length);
+
+		if (G_UNLIKELY (profile == NULL)) {
+			eom_debug_message (DEBUG_LCMS,
+					   "Invalid display profile set, "
+					   "not using it");
+		}
+
+		XFree (str);
+	}
+
+	if (profile == NULL) {
+		profile = cmsCreate_sRGBProfile ();
+		eom_debug_message (DEBUG_LCMS,
+				 "No valid display profile set, assuming sRGB");
+	}
+
+	return profile;
+}
+#endif
+
+static void
+update_image_pos (EomWindow *window)
+{
+	EomWindowPrivate *priv;
+	gint pos = -1, n_images = 0;
+
+	priv = window->priv;
+
+	n_images = eom_list_store_length (EOM_LIST_STORE (priv->store));
+
+	if (n_images > 0) {
+		pos = eom_list_store_get_pos_by_image (EOM_LIST_STORE (priv->store),
+						       priv->image);
+	}
+	/* Images: (image pos) / (n_total_images) */
+	eom_statusbar_set_image_number (EOM_STATUSBAR (priv->statusbar),
+					pos + 1,
+					n_images);
+
+}
+
+static void
+update_status_bar (EomWindow *window)
+{
+	EomWindowPrivate *priv;
+	char *str = NULL;
+
+	g_return_if_fail (EOM_IS_WINDOW (window));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = window->priv;
+
+	if (priv->image != NULL &&
+	    eom_image_has_data (priv->image, EOM_IMAGE_DATA_DIMENSION)) {
+		int zoom, width, height;
+		goffset bytes = 0;
+
+		zoom = floor (100 * eom_scroll_view_get_zoom (EOM_SCROLL_VIEW (priv->view)) + 0.5);
+
+		eom_image_get_size (priv->image, &width, &height);
+
+		bytes = eom_image_get_bytes (priv->image);
+
+		if ((width > 0) && (height > 0)) {
+			char *size_string;
+
+				size_string = g_format_size (bytes);
+
+			/* Translators: This is the string displayed in the statusbar
+			 * The tokens are from left to right:
+			 * - image width
+			 * - image height
+			 * - image size in bytes
+			 * - zoom in percent */
+			str = g_strdup_printf (ngettext("%i × %i pixel  %s    %i%%",
+							"%i × %i pixels  %s    %i%%", height),
+						width,
+						height,
+						size_string,
+						zoom);
+
+			g_free (size_string);
+		}
+
+		update_image_pos (window);
+	}
+
+	gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar),
+			   priv->image_info_message_cid);
+
+	gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar),
+			    priv->image_info_message_cid, str ? str : "");
+
+	g_free (str);
+}
+
+static void
+eom_window_set_message_area (EomWindow *window,
+		             GtkWidget *message_area)
+{
+	if (window->priv->message_area == message_area)
+		return;
+
+	if (window->priv->message_area != NULL)
+		gtk_widget_destroy (window->priv->message_area);
+
+	window->priv->message_area = message_area;
+
+	if (message_area == NULL) return;
+
+	gtk_box_pack_start (GTK_BOX (window->priv->cbox),
+			    window->priv->message_area,
+			    FALSE,
+			    FALSE,
+			    0);
+
+	g_object_add_weak_pointer (G_OBJECT (window->priv->message_area),
+				   (void *) &window->priv->message_area);
+}
+
+static void
+update_action_groups_state (EomWindow *window)
+{
+	EomWindowPrivate *priv;
+	GtkAction *action_collection;
+	GtkAction *action_sidebar;
+	GtkAction *action_fscreen;
+	GtkAction *action_sshow;
+	GtkAction *action_print;
+	gboolean print_disabled = FALSE;
+	gboolean show_image_collection = FALSE;<--- Variable 'show_image_collection' is assigned a value that is never used.
+	gint n_images = 0;
+
+	g_return_if_fail (EOM_IS_WINDOW (window));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = window->priv;
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action_collection =
+		gtk_action_group_get_action (priv->actions_window,
+					     "ViewImageCollection");
+
+	action_sidebar =
+		gtk_action_group_get_action (priv->actions_window,
+					     "ViewSidebar");
+
+	action_fscreen =
+		gtk_action_group_get_action (priv->actions_image,
+					     "ViewFullscreen");
+
+	action_sshow =
+		gtk_action_group_get_action (priv->actions_collection,
+					     "ViewSlideshow");
+
+	action_print =
+		gtk_action_group_get_action (priv->actions_image,
+					     "ImagePrint");
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	g_assert (action_collection != NULL);
+	g_assert (action_sidebar != NULL);
+	g_assert (action_fscreen != NULL);
+	g_assert (action_sshow != NULL);
+	g_assert (action_print != NULL);
+
+	if (priv->store != NULL) {
+		n_images = eom_list_store_length (EOM_LIST_STORE (priv->store));
+	}
+
+	if (n_images == 0) {
+		gtk_widget_hide (priv->layout);
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		gtk_action_group_set_sensitive (priv->actions_window,      TRUE);
+		gtk_action_group_set_sensitive (priv->actions_image,       FALSE);
+		gtk_action_group_set_sensitive (priv->actions_collection,  FALSE);
+
+		gtk_action_set_sensitive (action_fscreen, FALSE);
+		gtk_action_set_sensitive (action_sshow,   FALSE);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+
+		/* If there are no images on model, initialization
+ 		   stops here. */
+		if (priv->status == EOM_WINDOW_STATUS_INIT) {
+			priv->status = EOM_WINDOW_STATUS_NORMAL;
+		}
+	} else {
+		if (priv->flags & EOM_STARTUP_DISABLE_COLLECTION) {
+			g_settings_set_boolean (priv->ui_settings, EOM_CONF_UI_IMAGE_COLLECTION, FALSE);
+
+			show_image_collection = FALSE;
+		} else {
+			show_image_collection =
+				g_settings_get_boolean (priv->ui_settings, EOM_CONF_UI_IMAGE_COLLECTION);
+		}
+
+		show_image_collection = show_image_collection &&
+					n_images > 1 &&
+					priv->mode != EOM_WINDOW_MODE_SLIDESHOW;
+
+		gtk_widget_show (priv->layout);
+
+		if (show_image_collection)
+			gtk_widget_show (priv->nav);
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action_collection),
+					      show_image_collection);
+
+		gtk_action_group_set_sensitive (priv->actions_window, TRUE);
+		gtk_action_group_set_sensitive (priv->actions_image,  TRUE);
+
+		gtk_action_set_sensitive (action_fscreen, TRUE);
+
+		if (n_images == 1) {
+			gtk_action_group_set_sensitive (priv->actions_collection,  FALSE);
+			gtk_action_set_sensitive (action_collection, FALSE);
+			gtk_action_set_sensitive (action_sshow, FALSE);
+		} else {
+			gtk_action_group_set_sensitive (priv->actions_collection,  TRUE);
+			gtk_action_set_sensitive (action_sshow, TRUE);
+		}
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+
+		if (show_image_collection)
+			gtk_widget_grab_focus (priv->thumbview);
+		else
+			gtk_widget_grab_focus (priv->view);
+	}
+
+	print_disabled = g_settings_get_boolean (priv->lockdown_settings,
+						EOM_CONF_LOCKDOWN_CAN_PRINT);
+
+	if (print_disabled) {
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		gtk_action_set_sensitive (action_print, FALSE);
+	}
+
+	if (eom_sidebar_is_empty (EOM_SIDEBAR (priv->sidebar))) {
+		gtk_action_set_sensitive (action_sidebar, FALSE);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+		gtk_widget_hide (priv->sidebar);
+	}
+}
+
+static void
+update_selection_ui_visibility (EomWindow *window)
+{
+	EomWindowPrivate *priv;
+	GtkAction *wallpaper_action;
+	gint n_selected;
+
+	priv = window->priv;
+
+	n_selected = eom_thumb_view_get_n_selected (EOM_THUMB_VIEW (priv->thumbview));
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	wallpaper_action =
+		gtk_action_group_get_action (priv->actions_image,
+					     "ImageSetAsWallpaper");
+
+	if (n_selected == 1) {
+		gtk_action_set_sensitive (wallpaper_action, TRUE);
+	} else {
+		gtk_action_set_sensitive (wallpaper_action, FALSE);
+	}
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+static gboolean
+add_file_to_recent_files (GFile *file)
+{
+	gchar *text_uri;
+	GFileInfo *file_info;
+	GtkRecentData *recent_data;
+	static gchar *groups[2] = { EOM_RECENT_FILES_GROUP , NULL };
+
+	if (file == NULL) return FALSE;
+
+	/* The password gets stripped here because ~/.recently-used.xbel is
+	 * readable by everyone (chmod 644). It also makes the workaround
+	 * for the bug with gtk_recent_info_get_uri_display() easier
+	 * (see the comment in eom_window_update_recent_files_menu()). */
+	text_uri = g_file_get_uri (file);
+
+	if (text_uri == NULL)
+		return FALSE;
+
+	file_info = g_file_query_info (file,
+				       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+				       0, NULL, NULL);
+	if (file_info == NULL)
+		return FALSE;
+
+	recent_data = g_slice_new (GtkRecentData);
+	recent_data->display_name = NULL;
+	recent_data->description = NULL;
+	recent_data->mime_type = (gchar *) g_file_info_get_content_type (file_info);
+	recent_data->app_name = EOM_RECENT_FILES_APP_NAME;
+	recent_data->app_exec = g_strjoin(" ", g_get_prgname (), "%u", NULL);
+	recent_data->groups = groups;
+	recent_data->is_private = FALSE;
+
+	gtk_recent_manager_add_full (gtk_recent_manager_get_default (),
+				     text_uri,
+				     recent_data);
+
+	g_free (recent_data->app_exec);
+	g_free (text_uri);
+	g_object_unref (file_info);
+
+	g_slice_free (GtkRecentData, recent_data);
+
+	return FALSE;
+}
+
+static void
+image_thumb_changed_cb (EomImage *image, gpointer data)
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+	GdkPixbuf *thumb;
+
+	g_return_if_fail (EOM_IS_WINDOW (data));
+
+	window = EOM_WINDOW (data);
+	priv = window->priv;
+
+	thumb = eom_image_get_thumbnail (image);
+
+	if (thumb != NULL) {
+		gtk_window_set_icon (GTK_WINDOW (window), thumb);
+
+		if (window->priv->properties_dlg != NULL) {
+			eom_properties_dialog_update (EOM_PROPERTIES_DIALOG (priv->properties_dlg),
+						      image);
+		}
+
+		g_object_unref (thumb);
+	} else if (!gtk_widget_get_visible (window->priv->nav)) {
+		gint img_pos = eom_list_store_get_pos_by_image (window->priv->store, image);
+		GtkTreePath *path = gtk_tree_path_new_from_indices (img_pos,-1);
+		GtkTreeIter iter;
+
+		gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->store), &iter, path);
+		eom_list_store_thumbnail_set (window->priv->store, &iter);
+		gtk_tree_path_free (path);
+	}
+}
+
+static void
+file_changed_info_bar_response (GtkInfoBar *info_bar,
+				gint response,
+				EomWindow *window)
+{
+	if (response == GTK_RESPONSE_YES) {
+		eom_window_reload_image (window);
+	}
+
+	window->priv->needs_reload_confirmation = TRUE;
+
+	eom_window_set_message_area (window, NULL);
+}
+static void
+image_file_changed_cb (EomImage *img, EomWindow *window)
+{
+	GtkWidget *info_bar;
+	gchar *text, *markup;
+	GtkWidget *image;
+	GtkWidget *label;
+	GtkWidget *hbox;
+
+	if (window->priv->needs_reload_confirmation == FALSE)
+		return;
+
+	if (!eom_image_is_modified (img)) {
+		/* Auto-reload when image is unmodified */
+		eom_window_reload_image (window);
+		return;
+	}
+
+	window->priv->needs_reload_confirmation = FALSE;
+
+	info_bar = gtk_info_bar_new_with_buttons (_("_Reload"),
+						  GTK_RESPONSE_YES,
+						  C_("MessageArea", "Hi_de"),
+						  GTK_RESPONSE_NO, NULL);
+	gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
+				       GTK_MESSAGE_QUESTION);
+	image = gtk_image_new_from_icon_name ("dialog-question",
+					  GTK_ICON_SIZE_DIALOG);
+	label = gtk_label_new (NULL);
+
+	/* The newline character is currently necessary due to a problem
+	 * with the automatic line break. */
+	text = g_strdup_printf (_("The image \"%s\" has been modified by an external application."
+				  "\nWould you like to reload it?"), eom_image_get_caption (img));
+	markup = g_markup_printf_escaped ("<b>%s</b>", text);
+	gtk_label_set_markup (GTK_LABEL (label), markup);
+	g_free (text);
+	g_free (markup);
+
+	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
+	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+	gtk_widget_set_halign (image, GTK_ALIGN_START);
+	gtk_widget_set_valign (image, GTK_ALIGN_END);
+	gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+	gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+	gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar))), hbox, TRUE, TRUE, 0);
+	gtk_widget_show_all (hbox);
+	gtk_widget_show (info_bar);
+
+	eom_window_set_message_area (window, info_bar);
+	g_signal_connect (info_bar, "response",
+			  G_CALLBACK (file_changed_info_bar_response), window);
+}
+
+static void
+eom_window_display_image (EomWindow *window, EomImage *image)
+{
+	EomWindowPrivate *priv;
+	GFile *file;
+
+	g_return_if_fail (EOM_IS_WINDOW (window));
+	g_return_if_fail (EOM_IS_IMAGE (image));
+
+	eom_debug (DEBUG_WINDOW);
+
+	g_assert (eom_image_has_data (image, EOM_IMAGE_DATA_IMAGE));
+
+	priv = window->priv;
+
+	if (image != NULL) {
+		g_signal_connect (image,
+				  "thumbnail_changed",
+				  G_CALLBACK (image_thumb_changed_cb),
+				  window);
+		g_signal_connect (image, "file-changed",
+				  G_CALLBACK (image_file_changed_cb),
+				  window);
+
+		image_thumb_changed_cb (image, window);
+	}
+
+	priv->needs_reload_confirmation = TRUE;
+
+	eom_scroll_view_set_image (EOM_SCROLL_VIEW (priv->view), image);
+
+	gtk_window_set_title (GTK_WINDOW (window), eom_image_get_caption (image));
+
+	update_status_bar (window);
+
+	file = eom_image_get_file (image);
+	g_idle_add_full (G_PRIORITY_LOW,
+			 (GSourceFunc) add_file_to_recent_files,
+			 file,
+			 (GDestroyNotify) g_object_unref);
+
+	eom_window_update_openwith_menu (window, image);
+}
+
+static void
+open_with_launch_application_cb (GtkAction *action, gpointer data) {
+	EomImage *image;
+	GAppInfo *app;
+	GFile *file;
+	GList *files = NULL;
+
+	image = EOM_IMAGE (data);
+	file = eom_image_get_file (image);
+
+	app = g_object_get_data (G_OBJECT (action), "app");
+	files = g_list_append (files, file);
+	g_app_info_launch (app,
+			   files,
+			   NULL, NULL);
+
+	g_object_unref (file);
+	g_list_free (files);
+}
+
+static void
+eom_window_update_openwith_menu (EomWindow *window, EomImage *image)
+{
+	gboolean edit_button_active;
+	GAppInfo *editor_app;
+	GFile *file;
+	GFileInfo *file_info;
+	GList *iter;
+	gchar *label, *tip;
+	const gchar *mime_type;
+	GtkAction *action;
+	EomWindowPrivate *priv;
+	GList *apps;
+	guint action_id = 0;
+	GIcon *app_icon;
+	char *path;
+	GtkWidget *menuitem;
+
+	priv = window->priv;
+
+	edit_button_active = FALSE;
+	editor_app = get_appinfo_for_editor (window);
+
+	file = eom_image_get_file (image);
+	file_info = g_file_query_info (file,
+				       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+				       0, NULL, NULL);
+
+	if (file_info == NULL)
+		return;
+	else {
+		mime_type = g_file_info_get_content_type (file_info);
+	}
+
+	if (priv->open_with_menu_id != 0) {
+		gtk_ui_manager_remove_ui (priv->ui_mgr, priv->open_with_menu_id);
+		priv->open_with_menu_id = 0;
+	}
+
+	if (priv->actions_open_with != NULL) {
+		gtk_ui_manager_remove_action_group (priv->ui_mgr, priv->actions_open_with);
+		g_object_unref (priv->actions_open_with);
+		priv->actions_open_with = NULL;
+	}
+
+	if (mime_type == NULL) {
+		g_object_unref (file_info);
+		return;
+	}
+
+	apps = g_app_info_get_all_for_type (mime_type);
+
+	g_object_unref (file_info);
+
+	if (!apps)
+		return;
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	priv->actions_open_with = gtk_action_group_new ("OpenWithActions");
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+	gtk_ui_manager_insert_action_group (priv->ui_mgr, priv->actions_open_with, -1);
+
+	priv->open_with_menu_id = gtk_ui_manager_new_merge_id (priv->ui_mgr);
+
+	for (iter = apps; iter; iter = iter->next) {
+		GAppInfo *app = iter->data;
+		gchar name[64];
+
+		if (editor_app != NULL && g_app_info_equal (editor_app, app)) {
+			edit_button_active = TRUE;
+		}
+
+		/* Do not include eom itself */
+		if (g_ascii_strcasecmp (g_app_info_get_executable (app),
+				                g_get_prgname ()) == 0) {
+			g_object_unref (app);
+			continue;
+		}
+
+		g_snprintf (name, sizeof (name), "OpenWith%u", action_id++);
+
+		label = g_strdup (g_app_info_get_name (app));
+		tip = g_strdup_printf (_("Use \"%s\" to open the selected image"), g_app_info_get_name (app));
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		action = gtk_action_new (name, label, tip, NULL);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+
+		app_icon = g_app_info_get_icon (app);
+		if (G_LIKELY (app_icon != NULL)) {
+			g_object_ref (app_icon);
+			G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+			gtk_action_set_gicon (action, app_icon);
+			G_GNUC_END_IGNORE_DEPRECATIONS;
+			g_object_unref (app_icon);
+		}
+
+		g_free (label);
+		g_free (tip);
+
+		g_object_set_data_full (G_OBJECT (action), "app", app,
+				                (GDestroyNotify) g_object_unref);
+
+		g_signal_connect (action,
+				          "activate",
+				          G_CALLBACK (open_with_launch_application_cb),
+				          image);
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		gtk_action_group_add_action (priv->actions_open_with, action);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+		g_object_unref (action);
+
+		gtk_ui_manager_add_ui (priv->ui_mgr,
+				        priv->open_with_menu_id,
+				        "/MainMenu/Image/ImageOpenWith/Applications Placeholder",
+				        name,
+				        name,
+				        GTK_UI_MANAGER_MENUITEM,
+				        FALSE);
+
+		gtk_ui_manager_add_ui (priv->ui_mgr,
+				        priv->open_with_menu_id,
+				        "/ThumbnailPopup/ImageOpenWith/Applications Placeholder",
+				        name,
+				        name,
+				        GTK_UI_MANAGER_MENUITEM,
+				        FALSE);
+		gtk_ui_manager_add_ui (priv->ui_mgr,
+				        priv->open_with_menu_id,
+				        "/ViewPopup/ImageOpenWith/Applications Placeholder",
+				        name,
+				        name,
+				        GTK_UI_MANAGER_MENUITEM,
+				        FALSE);
+
+		path = g_strdup_printf ("/MainMenu/Image/ImageOpenWith/Applications Placeholder/%s", name);
+
+		menuitem = gtk_ui_manager_get_widget (priv->ui_mgr, path);
+
+		/* Only force displaying the icon if it is an application icon */
+		gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menuitem), app_icon != NULL);
+
+		g_free (path);
+
+		path = g_strdup_printf ("/ThumbnailPopup/ImageOpenWith/Applications Placeholder/%s", name);
+
+		menuitem = gtk_ui_manager_get_widget (priv->ui_mgr, path);
+
+		/* Only force displaying the icon if it is an application icon */
+		gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menuitem), app_icon != NULL);
+
+		g_free (path);
+
+		path = g_strdup_printf ("/ViewPopup/ImageOpenWith/Applications Placeholder/%s", name);
+
+		menuitem = gtk_ui_manager_get_widget (priv->ui_mgr, path);
+
+		/* Only force displaying the icon if it is an application icon */
+		gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menuitem), app_icon != NULL);
+
+		g_free (path);
+	}
+
+	g_list_free (apps);
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action = gtk_action_group_get_action (window->priv->actions_image,
+		                                  "OpenEditor");
+	if (action != NULL) {
+		gtk_action_set_sensitive (action, edit_button_active);
+	}
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+static void
+eom_window_clear_load_job (EomWindow *window)
+{
+	EomWindowPrivate *priv = window->priv;
+
+	if (priv->load_job != NULL) {
+		if (!priv->load_job->finished)
+			eom_job_queue_remove_job (priv->load_job);
+
+		g_signal_handlers_disconnect_by_func (priv->load_job,
+						      eom_job_progress_cb,
+						      window);
+
+		g_signal_handlers_disconnect_by_func (priv->load_job,
+						      eom_job_load_cb,
+						      window);
+
+		eom_image_cancel_load (EOM_JOB_LOAD (priv->load_job)->image);
+
+		g_object_unref (priv->load_job);
+		priv->load_job = NULL;
+
+		/* Hide statusbar */
+		eom_statusbar_set_progress (EOM_STATUSBAR (priv->statusbar), 0);
+	}
+}
+
+static void
+eom_job_progress_cb (EomJobLoad *job, float progress, gpointer user_data)
+{
+	EomWindow *window;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+
+	eom_statusbar_set_progress (EOM_STATUSBAR (window->priv->statusbar),
+				    progress);
+}
+
+static void
+eom_job_save_progress_cb (EomJobSave *job, float progress, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+	EomWindow *window;
+
+	static EomImage *image = NULL;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+	priv = window->priv;
+
+	eom_statusbar_set_progress (EOM_STATUSBAR (priv->statusbar),
+				    progress);
+
+	if (image != job->current_image) {
+		gchar *str_image, *status_message;
+		guint n_images;
+
+		image = job->current_image;
+
+		n_images = g_list_length (job->images);
+
+		str_image = eom_image_get_uri_for_display (image);
+
+		/* Translators: This string is displayed in the statusbar
+		 * while saving images. The tokens are from left to right:
+		 * - the original filename
+		 * - the current image's position in the queue
+		 * - the total number of images queued for saving */
+		status_message = g_strdup_printf (_("Saving image \"%s\" (%u/%u)"),
+					          str_image,
+						  job->current_pos + 1,
+						  n_images);
+		g_free (str_image);
+
+		gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar),
+				   priv->image_info_message_cid);
+
+		gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar),
+				    priv->image_info_message_cid,
+				    status_message);
+
+		g_free (status_message);
+	}
+
+	if (progress == 1.0)
+		image = NULL;
+}
+
+static void
+eom_window_obtain_desired_size (EomImage  *image,
+				gint       width,
+				gint       height,
+				EomWindow *window)
+{
+	GdkScreen *screen;
+	GdkDisplay *display;
+	GdkRectangle monitor;
+	GtkAllocation allocation;
+	gint final_width, final_height;
+	gint screen_width, screen_height;
+	gint window_width, window_height;
+	gint img_width, img_height;
+	gint view_width, view_height;
+	gint deco_width, deco_height;
+
+	update_action_groups_state (window);
+
+	img_width = width;
+	img_height = height;
+
+	if (!gtk_widget_get_realized (window->priv->view)) {
+		gtk_widget_realize (window->priv->view);
+	}
+
+	gtk_widget_get_allocation (window->priv->view, &allocation);
+	view_width  = allocation.width;
+	view_height = allocation.height;
+
+	if (!gtk_widget_get_realized (GTK_WIDGET (window))) {
+		gtk_widget_realize (GTK_WIDGET (window));
+	}
+
+	gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
+	window_width  = allocation.width;
+	window_height = allocation.height;
+
+	screen = gtk_window_get_screen (GTK_WINDOW (window));
+	display = gdk_screen_get_display (screen);
+
+	gdk_monitor_get_geometry (gdk_display_get_monitor_at_window (display,
+								     gtk_widget_get_window (GTK_WIDGET (window))),
+				  &monitor);
+
+	screen_width  = monitor.width;
+	screen_height = monitor.height;
+
+	deco_width = window_width - view_width;
+	deco_height = window_height - view_height;
+
+	if (img_width > 0 && img_height > 0) {
+		if ((img_width + deco_width > screen_width) ||
+		    (img_height + deco_height > screen_height))
+		{
+			double factor;
+
+			if (img_width > img_height) {
+				factor = (screen_width * 0.75 - deco_width) / (double) img_width;
+			} else {
+				factor = (screen_height * 0.75 - deco_height) / (double) img_height;
+			}
+
+			img_width = img_width * factor;
+			img_height = img_height * factor;
+		}
+	}
+
+	final_width = MAX (EOM_WINDOW_MIN_WIDTH, img_width + deco_width);
+	final_height = MAX (EOM_WINDOW_MIN_HEIGHT, img_height + deco_height);
+
+	eom_debug_message (DEBUG_WINDOW, "Setting window size: %d x %d", final_width, final_height);
+
+	gtk_window_set_default_size (GTK_WINDOW (window), final_width, final_height);
+
+	g_signal_emit (window, signals[SIGNAL_PREPARED], 0);
+}
+
+static void
+eom_window_error_message_area_response (GtkInfoBar       *message_area,
+					gint              response_id,
+					EomWindow        *window)
+{
+	if (response_id != GTK_RESPONSE_OK) {
+		eom_window_set_message_area (window, NULL);
+
+		return;
+	}
+
+	/* Trigger loading for current image again */
+	eom_thumb_view_select_single (EOM_THUMB_VIEW (window->priv->thumbview),
+				      EOM_THUMB_VIEW_SELECT_CURRENT);
+}
+
+static void
+eom_job_load_cb (EomJobLoad *job, gpointer data)
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+	GtkAction *action_undo, *action_save;
+
+	g_return_if_fail (EOM_IS_WINDOW (data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	window = EOM_WINDOW (data);
+	priv = window->priv;
+
+	eom_statusbar_set_progress (EOM_STATUSBAR (priv->statusbar), 0.0);
+
+	gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+			   priv->image_info_message_cid);
+
+	if (priv->image != NULL) {
+		g_signal_handlers_disconnect_by_func (priv->image,
+						      image_thumb_changed_cb,
+						      window);
+		g_signal_handlers_disconnect_by_func (priv->image,
+						      image_file_changed_cb,
+						      window);
+
+		g_object_unref (priv->image);
+	}
+
+	priv->image = g_object_ref (job->image);
+
+	if (EOM_JOB (job)->error == NULL) {
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+		eom_image_apply_display_profile (job->image,
+						 priv->display_profile);
+#endif
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		gtk_action_group_set_sensitive (priv->actions_image, TRUE);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+
+		eom_window_display_image (window, job->image);
+	} else {
+		GtkWidget *message_area;
+
+		message_area = eom_image_load_error_message_area_new (
+					eom_image_get_caption (job->image),
+					EOM_JOB (job)->error);
+
+		g_signal_connect (message_area,
+				  "response",
+				  G_CALLBACK (eom_window_error_message_area_response),
+				  window);
+
+		gtk_window_set_icon (GTK_WINDOW (window), NULL);
+		gtk_window_set_title (GTK_WINDOW (window),
+				      eom_image_get_caption (job->image));
+
+		eom_window_set_message_area (window, message_area);
+
+		gtk_info_bar_set_default_response (GTK_INFO_BAR (message_area),
+						   GTK_RESPONSE_CANCEL);
+
+		gtk_widget_show (message_area);
+
+		update_status_bar (window);
+
+		eom_scroll_view_set_image (EOM_SCROLL_VIEW (priv->view), NULL);
+
+        	if (window->priv->status == EOM_WINDOW_STATUS_INIT) {
+			update_action_groups_state (window);
+
+			g_signal_emit (window, signals[SIGNAL_PREPARED], 0);
+		}
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		gtk_action_group_set_sensitive (priv->actions_image, FALSE);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+	}
+
+	eom_window_clear_load_job (window);
+
+	if (window->priv->status == EOM_WINDOW_STATUS_INIT) {
+		window->priv->status = EOM_WINDOW_STATUS_NORMAL;
+
+		g_signal_handlers_disconnect_by_func
+			(job->image,
+			 G_CALLBACK (eom_window_obtain_desired_size),
+			 window);
+	}
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action_save = gtk_action_group_get_action (priv->actions_image, "ImageSave");
+	action_undo = gtk_action_group_get_action (priv->actions_image, "EditUndo");
+
+	/* Set Save and Undo sensitive according to image state.
+	 * Respect lockdown in case of Save.*/
+	gtk_action_set_sensitive (action_save, (!priv->save_disabled && eom_image_is_modified (job->image)));
+	gtk_action_set_sensitive (action_undo, eom_image_is_modified (job->image));
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	g_object_unref (job->image);
+}
+
+static void
+eom_window_clear_transform_job (EomWindow *window)
+{
+	EomWindowPrivate *priv = window->priv;
+
+	if (priv->transform_job != NULL) {
+		if (!priv->transform_job->finished)
+			eom_job_queue_remove_job (priv->transform_job);
+
+		g_signal_handlers_disconnect_by_func (priv->transform_job,
+						      eom_job_transform_cb,
+						      window);
+		g_object_unref (priv->transform_job);
+		priv->transform_job = NULL;
+	}
+}
+
+static void
+eom_job_transform_cb (EomJobTransform *job, gpointer data)
+{
+	EomWindow *window;
+	GtkAction *action_undo, *action_save;
+	EomImage *image;
+
+	g_return_if_fail (EOM_IS_WINDOW (data));
+
+	window = EOM_WINDOW (data);
+
+	eom_window_clear_transform_job (window);
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action_undo =
+		gtk_action_group_get_action (window->priv->actions_image, "EditUndo");
+	action_save =
+		gtk_action_group_get_action (window->priv->actions_image, "ImageSave");
+
+	image = eom_window_get_image (window);
+
+	gtk_action_set_sensitive (action_undo, eom_image_is_modified (image));
+
+	if (!window->priv->save_disabled)
+	{
+		gtk_action_set_sensitive (action_save, eom_image_is_modified (image));
+	}
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+static void
+apply_transformation (EomWindow *window, EomTransform *trans)
+{
+	EomWindowPrivate *priv;
+	GList *images;
+
+	g_return_if_fail (EOM_IS_WINDOW (window));
+
+	priv = window->priv;
+
+	images = eom_thumb_view_get_selected_images (EOM_THUMB_VIEW (priv->thumbview));
+
+	eom_window_clear_transform_job (window);
+
+	priv->transform_job = eom_job_transform_new (images, trans);
+
+	g_signal_connect (priv->transform_job,
+			  "finished",
+			  G_CALLBACK (eom_job_transform_cb),
+			  window);
+
+	g_signal_connect (priv->transform_job,
+			  "progress",
+			  G_CALLBACK (eom_job_progress_cb),
+			  window);
+
+	eom_job_queue_add_job (priv->transform_job);
+}
+
+static void
+handle_image_selection_changed_cb (EomThumbView *thumbview, EomWindow *window)
+{
+	EomWindowPrivate *priv;
+	EomImage *image;
+	gchar *status_message;
+	gchar *str_image;
+
+	priv = window->priv;
+
+	if (eom_list_store_length (EOM_LIST_STORE (priv->store)) == 0) {
+		gtk_window_set_title (GTK_WINDOW (window),
+				      g_get_application_name());
+		gtk_statusbar_remove_all (GTK_STATUSBAR (priv->statusbar),
+					  priv->image_info_message_cid);
+		eom_scroll_view_set_image (EOM_SCROLL_VIEW (priv->view),
+					   NULL);
+	}
+
+	if (eom_thumb_view_get_n_selected (EOM_THUMB_VIEW (priv->thumbview)) == 0)
+		return;
+
+	update_selection_ui_visibility (window);
+
+	image = eom_thumb_view_get_first_selected_image (EOM_THUMB_VIEW (priv->thumbview));
+
+	g_assert (EOM_IS_IMAGE (image));
+
+	eom_window_clear_load_job (window);
+
+	eom_window_set_message_area (window, NULL);
+
+	gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar),
+			   priv->image_info_message_cid);
+
+	if (image == priv->image) {
+		update_status_bar (window);
+		return;
+	}
+
+	if (eom_image_has_data (image, EOM_IMAGE_DATA_IMAGE)) {
+		if (priv->image != NULL)
+			g_object_unref (priv->image);
+
+		priv->image = image;
+		eom_window_display_image (window, image);
+		return;
+	}
+
+	if (priv->status == EOM_WINDOW_STATUS_INIT) {
+		g_signal_connect (image,
+				  "size-prepared",
+				  G_CALLBACK (eom_window_obtain_desired_size),
+				  window);
+	}
+
+	priv->load_job = eom_job_load_new (image, EOM_IMAGE_DATA_ALL);
+
+	g_signal_connect (priv->load_job,
+			  "finished",
+			  G_CALLBACK (eom_job_load_cb),
+			  window);
+
+	g_signal_connect (priv->load_job,
+			  "progress",
+			  G_CALLBACK (eom_job_progress_cb),
+			  window);
+
+	eom_job_queue_add_job (priv->load_job);
+
+	str_image = eom_image_get_uri_for_display (image);
+
+	status_message = g_strdup_printf (_("Opening image \"%s\""),
+				          str_image);
+
+	g_free (str_image);
+
+	gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar),
+			    priv->image_info_message_cid, status_message);
+
+	g_free (status_message);
+}
+
+static void
+view_zoom_changed_cb (GtkWidget *widget, double zoom, gpointer user_data)
+{
+	EomWindow *window;
+	GtkAction *action_zoom_in;
+	GtkAction *action_zoom_out;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+
+	update_status_bar (window);
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action_zoom_in =
+		gtk_action_group_get_action (window->priv->actions_image,
+					     "ViewZoomIn");
+
+	action_zoom_out =
+		gtk_action_group_get_action (window->priv->actions_image,
+					     "ViewZoomOut");
+
+	gtk_action_set_sensitive (action_zoom_in,
+			!eom_scroll_view_get_zoom_is_max (EOM_SCROLL_VIEW (window->priv->view)));
+	gtk_action_set_sensitive (action_zoom_out,
+			!eom_scroll_view_get_zoom_is_min (EOM_SCROLL_VIEW (window->priv->view)));
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+static void
+eom_window_open_recent_cb (GtkAction *action, EomWindow *window)
+{
+	GtkRecentInfo *info;
+	const gchar *uri;
+	GSList *list = NULL;
+
+	info = g_object_get_data (G_OBJECT (action), "gtk-recent-info");
+	g_return_if_fail (info != NULL);
+
+	uri = gtk_recent_info_get_uri (info);
+	list = g_slist_prepend (list, g_strdup (uri));
+
+	eom_application_open_uri_list (EOM_APP,
+				       list,
+				       GDK_CURRENT_TIME,
+				       0,
+				       NULL);
+
+	g_slist_free_full (list, g_free);
+}
+
+static void
+file_open_dialog_response_cb (GtkWidget *chooser,
+			      gint       response_id,
+			      EomWindow  *ev_window)
+{
+	if (response_id == GTK_RESPONSE_OK) {
+		GSList *uris;
+
+		uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser));
+
+		eom_application_open_uri_list (EOM_APP,
+					       uris,
+					       GDK_CURRENT_TIME,
+					       0,
+					       NULL);
+
+		g_slist_free_full (uris, g_free);
+	}
+
+	gtk_widget_destroy (chooser);
+}
+
+static void
+eom_window_update_fullscreen_action (EomWindow *window)
+{
+	GtkAction *action;
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action = gtk_action_group_get_action (window->priv->actions_image,
+					      "ViewFullscreen");
+
+	g_signal_handlers_block_by_func
+		(action, G_CALLBACK (eom_window_cmd_fullscreen), window);
+
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+				      window->priv->mode == EOM_WINDOW_MODE_FULLSCREEN);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	g_signal_handlers_unblock_by_func
+		(action, G_CALLBACK (eom_window_cmd_fullscreen), window);
+}
+
+static void
+eom_window_update_slideshow_action (EomWindow *window)
+{
+	GtkAction *action;
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action = gtk_action_group_get_action (window->priv->actions_collection,
+					      "ViewSlideshow");
+
+	g_signal_handlers_block_by_func
+		(action, G_CALLBACK (eom_window_cmd_slideshow), window);
+
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+				      window->priv->mode == EOM_WINDOW_MODE_SLIDESHOW);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	g_signal_handlers_unblock_by_func
+		(action, G_CALLBACK (eom_window_cmd_slideshow), window);
+}
+
+static void
+eom_window_update_pause_slideshow_action (EomWindow *window)
+{
+	GtkAction *action;
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action = gtk_action_group_get_action (window->priv->actions_image,
+					      "PauseSlideshow");
+
+	g_signal_handlers_block_by_func
+		(action, G_CALLBACK (eom_window_cmd_pause_slideshow), window);
+
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+				      window->priv->mode != EOM_WINDOW_MODE_SLIDESHOW);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	g_signal_handlers_unblock_by_func
+		(action, G_CALLBACK (eom_window_cmd_pause_slideshow), window);
+}
+
+static void
+eom_window_update_fullscreen_popup (EomWindow *window)
+{
+	GtkWidget *popup = window->priv->fullscreen_popup;
+	GdkRectangle screen_rect;
+	GdkScreen *screen;
+	GdkDisplay *display;
+
+	g_return_if_fail (popup != NULL);
+
+	if (gtk_widget_get_window (GTK_WIDGET (window)) == NULL) return;
+
+	screen = gtk_widget_get_screen (GTK_WIDGET (window));
+	display = gdk_screen_get_display (screen);
+
+	gdk_monitor_get_geometry (gdk_display_get_monitor_at_window (display,
+								     gtk_widget_get_window (GTK_WIDGET (window))),
+				  &screen_rect);
+
+	gtk_widget_set_size_request (popup,
+				     screen_rect.width,
+				     -1);
+
+	gtk_window_move (GTK_WINDOW (popup), screen_rect.x, screen_rect.y);
+}
+
+static void
+screen_size_changed_cb (GdkScreen *screen, EomWindow *window)
+{
+	eom_window_update_fullscreen_popup (window);
+}
+
+static gboolean
+fullscreen_timeout_cb (gpointer data)
+{
+	EomWindow *window = EOM_WINDOW (data);
+
+	gtk_widget_hide (window->priv->fullscreen_popup);
+
+	eom_scroll_view_hide_cursor (EOM_SCROLL_VIEW (window->priv->view));
+
+	fullscreen_clear_timeout (window);
+
+	return FALSE;
+}
+
+static gboolean
+slideshow_is_loop_end (EomWindow *window)
+{
+	EomWindowPrivate *priv = window->priv;
+	EomImage *image = NULL;
+	gint pos;
+
+	image = eom_thumb_view_get_first_selected_image (EOM_THUMB_VIEW (priv->thumbview));
+
+	pos = eom_list_store_get_pos_by_image (priv->store, image);
+
+	return (pos == (eom_list_store_length (priv->store) - 1));
+}
+
+static gboolean
+slideshow_switch_cb (gpointer data)
+{
+	EomWindow *window = EOM_WINDOW (data);
+	EomWindowPrivate *priv = window->priv;
+
+	eom_debug (DEBUG_WINDOW);
+
+	if (priv->slideshow_random) {
+		eom_thumb_view_select_single (EOM_THUMB_VIEW (priv->thumbview),
+					      EOM_THUMB_VIEW_SELECT_RANDOM);
+		return TRUE;
+	}
+
+	if (!priv->slideshow_loop && slideshow_is_loop_end (window)) {
+		eom_window_stop_fullscreen (window, TRUE);
+		return FALSE;
+	}
+
+	eom_thumb_view_select_single (EOM_THUMB_VIEW (priv->thumbview),
+				      EOM_THUMB_VIEW_SELECT_RIGHT);
+
+	return TRUE;
+}
+
+static void
+fullscreen_clear_timeout (EomWindow *window)
+{
+	eom_debug (DEBUG_WINDOW);
+
+	if (window->priv->fullscreen_timeout_source != NULL) {
+		g_source_unref (window->priv->fullscreen_timeout_source);
+		g_source_destroy (window->priv->fullscreen_timeout_source);
+	}
+
+	window->priv->fullscreen_timeout_source = NULL;
+}
+
+static void
+fullscreen_set_timeout (EomWindow *window)
+{
+	GSource *source;
+
+	eom_debug (DEBUG_WINDOW);
+
+	fullscreen_clear_timeout (window);
+
+	source = g_timeout_source_new (EOM_WINDOW_FULLSCREEN_TIMEOUT);
+	g_source_set_callback (source, fullscreen_timeout_cb, window, NULL);
+
+	g_source_attach (source, NULL);
+
+	window->priv->fullscreen_timeout_source = source;
+
+	eom_scroll_view_show_cursor (EOM_SCROLL_VIEW (window->priv->view));
+}
+
+static void
+slideshow_clear_timeout (EomWindow *window)
+{
+	eom_debug (DEBUG_WINDOW);
+
+	if (window->priv->slideshow_switch_source != NULL) {
+		g_source_unref (window->priv->slideshow_switch_source);
+		g_source_destroy (window->priv->slideshow_switch_source);
+	}
+
+	window->priv->slideshow_switch_source = NULL;
+}
+
+static void
+slideshow_set_timeout (EomWindow *window)
+{
+	GSource *source;
+
+	eom_debug (DEBUG_WINDOW);
+
+	slideshow_clear_timeout (window);
+
+	if (window->priv->slideshow_switch_timeout <= 0)
+		return;
+
+	source = g_timeout_source_new (window->priv->slideshow_switch_timeout * 1000);
+	g_source_set_callback (source, slideshow_switch_cb, window, NULL);
+
+	g_source_attach (source, NULL);
+
+	window->priv->slideshow_switch_source = source;
+}
+
+static void
+show_fullscreen_popup (EomWindow *window)
+{
+	eom_debug (DEBUG_WINDOW);
+
+	if (!gtk_widget_get_visible (window->priv->fullscreen_popup)) {
+		gtk_widget_show_all (GTK_WIDGET (window->priv->fullscreen_popup));
+	}
+
+	fullscreen_set_timeout (window);
+}
+
+static gboolean
+fullscreen_motion_notify_cb (GtkWidget      *widget,
+			     GdkEventMotion *event,
+			     gpointer       user_data)
+{
+	EomWindow *window = EOM_WINDOW (user_data);
+
+	eom_debug (DEBUG_WINDOW);
+
+	if (event->y < EOM_WINDOW_FULLSCREEN_POPUP_THRESHOLD) {
+		show_fullscreen_popup (window);
+	} else {
+		fullscreen_set_timeout (window);
+	}
+
+	return FALSE;
+}
+
+static gboolean
+fullscreen_leave_notify_cb (GtkWidget *widget,
+			    GdkEventCrossing *event,
+			    gpointer user_data)
+{
+	EomWindow *window = EOM_WINDOW (user_data);
+
+	eom_debug (DEBUG_WINDOW);
+
+	fullscreen_clear_timeout (window);
+
+	return FALSE;
+}
+
+static void
+exit_fullscreen_button_clicked_cb (GtkWidget *button, EomWindow *window)
+{
+	GtkAction *action;
+
+	eom_debug (DEBUG_WINDOW);
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	if (window->priv->mode == EOM_WINDOW_MODE_SLIDESHOW) {
+		action = gtk_action_group_get_action (window->priv->actions_collection,
+						      "ViewSlideshow");
+	} else {
+		action = gtk_action_group_get_action (window->priv->actions_image,
+						      "ViewFullscreen");
+	}
+	g_return_if_fail (action != NULL);
+
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+static GtkWidget *
+eom_window_get_exit_fullscreen_button (EomWindow *window)
+{
+	GtkWidget *button;
+
+	button = gtk_button_new_with_mnemonic (_("Leave Fullscreen"));
+	gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name ("view-restore", GTK_ICON_SIZE_BUTTON));
+
+	g_signal_connect (button, "clicked",
+			  G_CALLBACK (exit_fullscreen_button_clicked_cb),
+			  window);
+
+	return button;
+}
+
+static GtkWidget *
+eom_window_create_fullscreen_popup (EomWindow *window)
+{
+	GtkWidget *popup;
+	GtkWidget *hbox;
+	GtkWidget *button;
+	GtkWidget *toolbar;
+	GdkScreen *screen;
+
+	eom_debug (DEBUG_WINDOW);
+
+	popup = gtk_window_new (GTK_WINDOW_POPUP);
+
+	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+	gtk_container_add (GTK_CONTAINER (popup), hbox);
+
+	toolbar = gtk_ui_manager_get_widget (window->priv->ui_mgr,
+					     "/FullscreenToolbar");
+	g_assert (GTK_IS_WIDGET (toolbar));
+	gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
+	gtk_box_pack_start (GTK_BOX (hbox), toolbar, TRUE, TRUE, 0);
+
+	button = eom_window_get_exit_fullscreen_button (window);
+	gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+	gtk_window_set_resizable (GTK_WINDOW (popup), FALSE);
+
+	screen = gtk_widget_get_screen (GTK_WIDGET (window));
+
+	g_signal_connect_object (screen, "size-changed",
+			         G_CALLBACK (screen_size_changed_cb),
+				 window, 0);
+
+	g_signal_connect (popup,
+			  "enter-notify-event",
+			  G_CALLBACK (fullscreen_leave_notify_cb),
+			  window);
+
+	gtk_window_set_screen (GTK_WINDOW (popup), screen);
+
+	return popup;
+}
+
+static void
+update_ui_visibility (EomWindow *window)
+{
+	EomWindowPrivate *priv;
+
+	GtkAction *action;
+	GtkWidget *menubar;
+
+	gboolean fullscreen_mode, visible;
+
+	g_return_if_fail (EOM_IS_WINDOW (window));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = window->priv;
+
+	fullscreen_mode = priv->mode == EOM_WINDOW_MODE_FULLSCREEN ||
+			  priv->mode == EOM_WINDOW_MODE_SLIDESHOW;
+
+	menubar = gtk_ui_manager_get_widget (priv->ui_mgr, "/MainMenu");
+	g_assert (GTK_IS_WIDGET (menubar));
+
+	visible = g_settings_get_boolean (priv->ui_settings, EOM_CONF_UI_TOOLBAR);
+	visible = visible && !fullscreen_mode;
+
+	action = gtk_ui_manager_get_action (priv->ui_mgr, "/MainMenu/View/ToolbarToggle");
+	g_assert (action != NULL);
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+	g_object_set (G_OBJECT (priv->toolbar), "visible", visible, NULL);
+
+	visible = g_settings_get_boolean (priv->ui_settings, EOM_CONF_UI_STATUSBAR);
+	visible = visible && !fullscreen_mode;
+
+	action = gtk_ui_manager_get_action (priv->ui_mgr, "/MainMenu/View/StatusbarToggle");
+	g_assert (action != NULL);
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+	g_object_set (G_OBJECT (priv->statusbar), "visible", visible, NULL);
+
+	if (priv->status != EOM_WINDOW_STATUS_INIT) {
+		visible = g_settings_get_boolean (priv->ui_settings, EOM_CONF_UI_IMAGE_COLLECTION);
+		visible = visible && priv->mode != EOM_WINDOW_MODE_SLIDESHOW;
+		action = gtk_ui_manager_get_action (priv->ui_mgr, "/MainMenu/View/ImageCollectionToggle");
+		g_assert (action != NULL);
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+		if (visible) {
+			gtk_widget_show (priv->nav);
+		} else {
+			gtk_widget_hide (priv->nav);
+		}
+	}
+
+	visible = g_settings_get_boolean (priv->ui_settings, EOM_CONF_UI_SIDEBAR);
+	visible = visible && !fullscreen_mode;
+	action = gtk_ui_manager_get_action (priv->ui_mgr, "/MainMenu/View/SidebarToggle");
+	g_assert (action != NULL);
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+	if (visible) {
+		gtk_widget_show (priv->sidebar);
+	} else {
+		gtk_widget_hide (priv->sidebar);
+	}
+
+	if (priv->fullscreen_popup != NULL) {
+		gtk_widget_hide (priv->fullscreen_popup);
+	}
+}
+
+static void
+eom_window_inhibit_screensaver (EomWindow *window)
+{
+	EomWindowPrivate *priv = window->priv;
+
+	g_return_if_fail (priv->fullscreen_idle_inhibit_cookie == 0);
+
+	eom_debug (DEBUG_WINDOW);
+
+	window->priv->fullscreen_idle_inhibit_cookie =
+		gtk_application_inhibit (GTK_APPLICATION (EOM_APP),
+		                         GTK_WINDOW (window),
+		                         GTK_APPLICATION_INHIBIT_IDLE,
+		                         _("Viewing a slideshow"));
+}
+
+static void
+eom_window_uninhibit_screensaver (EomWindow *window)
+{
+	EomWindowPrivate *priv = window->priv;
+
+	if (G_UNLIKELY (priv->fullscreen_idle_inhibit_cookie == 0))
+		return;
+
+	eom_debug (DEBUG_WINDOW);
+
+	gtk_application_uninhibit (GTK_APPLICATION (EOM_APP),
+	                           priv->fullscreen_idle_inhibit_cookie);
+	priv->fullscreen_idle_inhibit_cookie = 0;
+}
+
+static void
+eom_window_run_fullscreen (EomWindow *window, gboolean slideshow)
+{
+	static const GdkRGBA black = { 0., 0., 0., 1.};
+
+	EomWindowPrivate *priv;
+	GtkWidget *menubar;
+	gboolean upscale;
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = window->priv;
+
+	if (slideshow) {
+		priv->mode = EOM_WINDOW_MODE_SLIDESHOW;
+	} else {
+		/* Stop the timer if we come from slideshowing */
+		if (priv->mode == EOM_WINDOW_MODE_SLIDESHOW)
+			slideshow_clear_timeout (window);
+
+		priv->mode = EOM_WINDOW_MODE_FULLSCREEN;
+	}
+
+	if (window->priv->fullscreen_popup == NULL)
+		priv->fullscreen_popup
+			= eom_window_create_fullscreen_popup (window);
+
+	update_ui_visibility (window);
+
+	menubar = gtk_ui_manager_get_widget (priv->ui_mgr, "/MainMenu");
+	g_assert (GTK_IS_WIDGET (menubar));
+	gtk_widget_hide (menubar);
+
+	g_signal_connect (priv->view,
+			  "motion-notify-event",
+			  G_CALLBACK (fullscreen_motion_notify_cb),
+			  window);
+
+	g_signal_connect (priv->view,
+			  "leave-notify-event",
+			  G_CALLBACK (fullscreen_leave_notify_cb),
+			  window);
+
+	g_signal_connect (priv->thumbview,
+			  "motion-notify-event",
+			  G_CALLBACK (fullscreen_motion_notify_cb),
+			  window);
+
+	g_signal_connect (priv->thumbview,
+			  "leave-notify-event",
+			  G_CALLBACK (fullscreen_leave_notify_cb),
+			  window);
+
+	fullscreen_set_timeout (window);
+
+	if (slideshow) {
+		priv->slideshow_random =
+				g_settings_get_boolean (priv->fullscreen_settings,
+						       EOM_CONF_FULLSCREEN_RANDOM);
+
+		priv->slideshow_loop =
+				g_settings_get_boolean (priv->fullscreen_settings,
+						       EOM_CONF_FULLSCREEN_LOOP);
+
+		priv->slideshow_switch_timeout =
+				g_settings_get_int (priv->fullscreen_settings,
+						      EOM_CONF_FULLSCREEN_SECONDS);
+
+		slideshow_set_timeout (window);
+	}
+
+	upscale = g_settings_get_boolean (priv->fullscreen_settings,
+					 EOM_CONF_FULLSCREEN_UPSCALE);
+
+	eom_scroll_view_set_zoom_upscale (EOM_SCROLL_VIEW (priv->view),
+					  upscale);
+
+	gtk_widget_grab_focus (priv->view);
+
+	eom_scroll_view_override_bg_color (EOM_SCROLL_VIEW (window->priv->view),
+	                                   &black);
+
+	gtk_window_fullscreen (GTK_WINDOW (window));
+	eom_window_update_fullscreen_popup (window);
+
+	eom_window_inhibit_screensaver (window);
+
+	/* Update both actions as we could've already been in one those modes */
+	eom_window_update_slideshow_action (window);
+	eom_window_update_fullscreen_action (window);
+	eom_window_update_pause_slideshow_action (window);
+}
+
+static void
+eom_window_stop_fullscreen (EomWindow *window, gboolean slideshow)
+{
+	EomWindowPrivate *priv;
+	GtkWidget *menubar;
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = window->priv;
+
+	if (priv->mode != EOM_WINDOW_MODE_SLIDESHOW &&
+	    priv->mode != EOM_WINDOW_MODE_FULLSCREEN) return;
+
+	priv->mode = EOM_WINDOW_MODE_NORMAL;
+
+	fullscreen_clear_timeout (window);
+
+	if (slideshow) {
+		slideshow_clear_timeout (window);
+	}
+
+	g_signal_handlers_disconnect_by_func (priv->view,
+					      (gpointer) fullscreen_motion_notify_cb,
+					      window);
+
+	g_signal_handlers_disconnect_by_func (priv->view,
+					      (gpointer) fullscreen_leave_notify_cb,
+					      window);
+
+	g_signal_handlers_disconnect_by_func (priv->thumbview,
+					      (gpointer) fullscreen_motion_notify_cb,
+					      window);
+
+	g_signal_handlers_disconnect_by_func (priv->thumbview,
+					      (gpointer) fullscreen_leave_notify_cb,
+					      window);
+
+	update_ui_visibility (window);
+
+	menubar = gtk_ui_manager_get_widget (priv->ui_mgr, "/MainMenu");
+	g_assert (GTK_IS_WIDGET (menubar));
+	gtk_widget_show (menubar);
+
+	eom_scroll_view_set_zoom_upscale (EOM_SCROLL_VIEW (priv->view), FALSE);
+
+	eom_scroll_view_override_bg_color (EOM_SCROLL_VIEW (window->priv->view),
+					   NULL);
+	gtk_window_unfullscreen (GTK_WINDOW (window));
+
+	if (slideshow) {
+		eom_window_update_slideshow_action (window);
+	} else {
+		eom_window_update_fullscreen_action (window);
+	}
+
+	eom_scroll_view_show_cursor (EOM_SCROLL_VIEW (priv->view));
+
+	eom_window_uninhibit_screensaver (window);
+}
+
+static void
+eom_window_print (EomWindow *window)
+{
+	GtkWidget *dialog;
+	GError *error = NULL;
+	GtkPrintOperation *print;
+	GtkPrintOperationResult res;
+	GtkPageSetup *page_setup;
+	GtkPrintSettings *print_settings;
+	gboolean page_setup_disabled = FALSE;
+
+	eom_debug (DEBUG_PRINTING);
+
+	print_settings = eom_print_get_print_settings ();
+
+	/* Make sure the window stays valid while printing */
+	g_object_ref (window);
+
+	if (window->priv->page_setup != NULL)
+		page_setup = g_object_ref (window->priv->page_setup);
+	else
+		page_setup = eom_print_get_page_setup ();
+
+	print = eom_print_operation_new (window->priv->image,
+					 print_settings,
+					 page_setup);
+
+	// Disable page setup options if they are locked down
+	page_setup_disabled = g_settings_get_boolean (window->priv->lockdown_settings,
+						      EOM_CONF_LOCKDOWN_CAN_SETUP_PAGE);
+	if (page_setup_disabled)
+		gtk_print_operation_set_embed_page_setup (print, FALSE);
+
+	res = gtk_print_operation_run (print,
+				       GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+				       GTK_WINDOW (window), &error);
+
+	if (res == GTK_PRINT_OPERATION_RESULT_ERROR) {
+		dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+						 GTK_DIALOG_DESTROY_WITH_PARENT,
+						 GTK_MESSAGE_ERROR,
+						 GTK_BUTTONS_CLOSE,
+						 _("Error printing file:\n%s"),
+						 error->message);
+		g_signal_connect (dialog, "response",
+				  G_CALLBACK (gtk_widget_destroy), NULL);
+		gtk_widget_show (dialog);
+		g_error_free (error);
+	} else if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
+		GtkPageSetup *new_page_setup;
+		eom_print_set_print_settings (gtk_print_operation_get_print_settings (print));
+		new_page_setup = gtk_print_operation_get_default_page_setup (print);
+		if (window->priv->page_setup != NULL)
+			g_object_unref (window->priv->page_setup);
+		window->priv->page_setup = g_object_ref (new_page_setup);
+		eom_print_set_page_setup (window->priv->page_setup);
+	}
+
+	if (page_setup != NULL)
+		g_object_unref (page_setup);
+	g_object_unref (print_settings);
+	g_object_unref (window);
+}
+
+static void
+eom_window_cmd_file_open (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+        EomImage *current;
+	GtkWidget *dlg;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+
+        priv = window->priv;
+
+	dlg = eom_file_chooser_new (GTK_FILE_CHOOSER_ACTION_OPEN);
+	gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (window));
+
+	current = eom_thumb_view_get_first_selected_image (EOM_THUMB_VIEW (priv->thumbview));
+
+	if (current != NULL) {
+		gchar *dir_uri, *file_uri;
+
+		file_uri = eom_image_get_uri_for_display (current);
+		dir_uri = g_path_get_dirname (file_uri);
+
+	        gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg),
+                                                         dir_uri);
+		g_free (file_uri);
+		g_free (dir_uri);
+		g_object_unref (current);
+	} else {
+		/* If desired by the user,
+		   fallback to the XDG_PICTURES_DIR (if available) */
+		const gchar *pics_dir;
+		gboolean use_fallback;
+
+		use_fallback = g_settings_get_boolean (priv->ui_settings,
+					   EOM_CONF_UI_FILECHOOSER_XDG_FALLBACK);
+		pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
+		if (use_fallback && pics_dir) {
+			gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dlg),
+							     pics_dir);
+		}
+	}
+
+	g_signal_connect (dlg, "response",
+			  G_CALLBACK (file_open_dialog_response_cb),
+			  window);
+
+	gtk_widget_show_all (dlg);
+}
+
+static void
+eom_job_close_save_cb (EomJobSave *job, gpointer user_data)
+{
+	EomWindow *window = EOM_WINDOW (user_data);
+
+	g_signal_handlers_disconnect_by_func (job,
+					      eom_job_close_save_cb,
+					      window);
+
+	gtk_widget_destroy (GTK_WIDGET (window));
+}
+
+static void
+close_confirmation_dialog_response_handler (EomCloseConfirmationDialog *dlg,
+					    gint                        response_id,
+					    EomWindow                  *window)
+{
+	GList *selected_images;
+	EomWindowPrivate *priv;
+
+	priv = window->priv;
+
+	switch (response_id)
+	{
+		case GTK_RESPONSE_YES:
+			/* save selected images */
+			selected_images = eom_close_confirmation_dialog_get_selected_images (dlg);
+			if (eom_window_save_images (window, selected_images)) {
+				g_signal_connect (priv->save_job,
+							  "finished",
+							  G_CALLBACK (eom_job_close_save_cb),
+							  window);
+
+				eom_job_queue_add_job (priv->save_job);
+			}
+
+			break;
+
+		case GTK_RESPONSE_NO:
+			/* dont save */
+			gtk_widget_destroy (GTK_WIDGET (window));
+			break;
+
+		default:
+			/* Cancel */
+			gtk_widget_destroy (GTK_WIDGET (dlg));
+			break;
+	}
+}
+
+static gboolean
+eom_window_unsaved_images_confirm (EomWindow *window)
+{
+	EomWindowPrivate *priv;
+	gboolean disabled;
+	GtkWidget *dialog;
+	GList *list;
+	EomImage *image;
+	GtkTreeIter iter;
+
+	priv = window->priv;
+
+	disabled = g_settings_get_boolean(priv->ui_settings,
+					EOM_CONF_UI_DISABLE_CLOSE_CONFIRMATION);
+	disabled |= window->priv->save_disabled;
+	if (disabled || !priv->store) {
+		return FALSE;
+	}
+
+	list = NULL;
+	if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), &iter)) {
+		do {
+			gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
+					    EOM_LIST_STORE_EOM_IMAGE, &image,
+					    -1);
+			if (!image)
+				continue;
+
+			if (eom_image_is_modified (image)) {
+				list = g_list_prepend (list, image);
+			}
+		} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), &iter));
+	}
+
+	if (list) {
+		list = g_list_reverse (list);
+		dialog = eom_close_confirmation_dialog_new (GTK_WINDOW (window),
+							    list);
+
+		g_list_free (list);
+		g_signal_connect (dialog,
+				  "response",
+				  G_CALLBACK (close_confirmation_dialog_response_handler),
+				  window);
+		gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+
+		gtk_widget_show (dialog);
+		return TRUE;
+
+	}
+	return FALSE;
+}
+
+static void
+eom_window_cmd_close_window (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+	priv = window->priv;
+
+	if (priv->save_job != NULL) {
+		eom_window_finish_saving (window);
+	}
+
+	if (!eom_window_unsaved_images_confirm (window)) {
+		gtk_widget_destroy (GTK_WIDGET (user_data));
+	}
+}
+
+static void
+eom_window_cmd_preferences (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window;
+	GtkWidget *pref_dlg;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+
+	pref_dlg = eom_preferences_dialog_get_instance (GTK_WINDOW (window));
+
+	gtk_widget_show (pref_dlg);
+}
+
+#define EOM_TB_EDITOR_DLG_RESET_RESPONSE 128
+
+static void
+eom_window_cmd_edit_toolbar_cb (GtkDialog *dialog, gint response, gpointer data)
+{
+	EomWindow *window = EOM_WINDOW (data);
+
+	if (response == EOM_TB_EDITOR_DLG_RESET_RESPONSE) {
+		EggToolbarsModel *model;
+		EggToolbarEditor *editor;
+
+		editor = g_object_get_data (G_OBJECT (dialog),
+					    "EggToolbarEditor");
+
+		g_return_if_fail (editor != NULL);
+
+		egg_editable_toolbar_set_edit_mode
+			(EGG_EDITABLE_TOOLBAR (window->priv->toolbar), FALSE);
+
+		eom_application_reset_toolbars_model (EOM_APP);
+		model = eom_application_get_toolbars_model (EOM_APP);
+		egg_editable_toolbar_set_model
+			(EGG_EDITABLE_TOOLBAR (window->priv->toolbar), model);
+		egg_toolbar_editor_set_model (editor, model);
+
+		/* Toolbar would be uneditable now otherwise */
+		egg_editable_toolbar_set_edit_mode
+			(EGG_EDITABLE_TOOLBAR (window->priv->toolbar), TRUE);
+	} else if (response == GTK_RESPONSE_HELP) {
+		eom_util_show_help ("eom-toolbareditor", NULL);
+	} else {
+		egg_editable_toolbar_set_edit_mode
+			(EGG_EDITABLE_TOOLBAR (window->priv->toolbar), FALSE);
+
+		eom_application_save_toolbars_model (EOM_APP);
+
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+	}
+}
+
+static void
+eom_window_cmd_edit_toolbar (GtkAction *action, gpointer *user_data)
+{
+	EomWindow *window;
+	GtkWidget *dialog;
+	GtkWidget *editor;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+
+	dialog = gtk_dialog_new_with_buttons (_("Toolbar Editor"),
+					      GTK_WINDOW (window),
+				              GTK_DIALOG_DESTROY_WITH_PARENT,
+					      _("_Reset to Default"),
+					      EOM_TB_EDITOR_DLG_RESET_RESPONSE,
+ 					      "gtk-close",
+					      GTK_RESPONSE_CLOSE,
+					      "gtk-help",
+					      GTK_RESPONSE_HELP,
+					      NULL);
+
+	gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+					 GTK_RESPONSE_CLOSE);
+
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+
+	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
+
+	gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 400);
+
+	editor = egg_toolbar_editor_new (window->priv->ui_mgr,
+					 eom_application_get_toolbars_model (EOM_APP));
+
+	gtk_container_set_border_width (GTK_CONTAINER (editor), 5);
+
+	// Use as much vertical space as available
+	gtk_widget_set_vexpand (GTK_WIDGET (editor), TRUE);
+
+	gtk_box_set_spacing (GTK_BOX (EGG_TOOLBAR_EDITOR (editor)), 5);
+
+	gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), editor);
+
+	egg_editable_toolbar_set_edit_mode
+		(EGG_EDITABLE_TOOLBAR (window->priv->toolbar), TRUE);
+
+	g_object_set_data (G_OBJECT (dialog), "EggToolbarEditor", editor);
+
+	g_signal_connect (dialog,
+                          "response",
+			  G_CALLBACK (eom_window_cmd_edit_toolbar_cb),
+			  window);
+
+	gtk_widget_show_all (dialog);
+}
+
+static void
+eom_window_cmd_help (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+
+	eom_util_show_help (NULL, GTK_WINDOW (window));
+}
+
+#define ABOUT_GROUP "About"
+#define EMAILIFY(string) (g_strdelimit ((string), "%", '@'))
+
+static void
+eom_window_cmd_about (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	const char *license[] = {
+		N_("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.\n"),
+		N_("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.\n"),
+		N_("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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.")
+	};
+
+	char *license_trans;
+	GKeyFile *key_file;
+	GBytes *bytes;
+	const guint8 *data;
+	gsize data_len;
+	GError *error = NULL;
+	char **authors, **documenters;
+	gsize n_authors = 0, n_documenters = 0 , i;
+
+	bytes = g_resources_lookup_data ("/org/mate/eom/ui/eom.about", G_RESOURCE_LOOKUP_FLAGS_NONE, &error);
+	g_assert_no_error (error);
+
+	data = g_bytes_get_data (bytes, &data_len);
+	key_file = g_key_file_new ();
+	g_key_file_load_from_data (key_file, (const char *) data, data_len, 0, &error);
+	g_assert_no_error (error);
+
+	authors = g_key_file_get_string_list (key_file, ABOUT_GROUP, "Authors", &n_authors, NULL);
+	documenters = g_key_file_get_string_list (key_file, ABOUT_GROUP, "Documenters", &n_documenters, NULL);
+
+	g_key_file_free (key_file);
+	g_bytes_unref (bytes);
+
+	for (i = 0; i < n_authors; ++i)
+		authors[i] = EMAILIFY (authors[i]);
+	for (i = 0; i < n_documenters; ++i)
+		documenters[i] = EMAILIFY (documenters[i]);
+
+	license_trans = g_strconcat (_(license[0]), "\n", _(license[1]), "\n", _(license[2]), "\n", NULL);
+
+	window = EOM_WINDOW (user_data);
+
+	gtk_show_about_dialog (GTK_WINDOW (window),
+			       "program-name", _("Eye of MATE"),
+			       "title", _("About Eye of MATE"),
+			       "version", VERSION,
+			       "copyright", _("Copyright \xc2\xa9 2000-2010 Free Software Foundation, Inc.\n"
+			                      "Copyright \xc2\xa9 2011 Perberos\n"
+			                      "Copyright \xc2\xa9 2012-2020 MATE developers"),
+			       "comments",_("Eye of MATE is a simple graphics viewer for the MATE Desktop Environment."),
+			       "authors", authors,
+			       "documenters", documenters,
+			       "translator-credits", _("translator-credits"),
+			       "website", "http://www.mate-desktop.org/",
+			       "logo-icon-name", "eom",
+			       "wrap-license", TRUE,
+			       "license", license_trans,
+			       NULL);
+
+	g_strfreev (authors);
+	g_strfreev (documenters);
+	g_free (license_trans);
+}
+
+static void
+eom_window_cmd_show_hide_bar (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+	gboolean visible;
+	const gchar *action_name;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+	priv = window->priv;
+
+	if (priv->mode != EOM_WINDOW_MODE_NORMAL &&
+            priv->mode != EOM_WINDOW_MODE_FULLSCREEN) return;
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	visible = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+	action_name = gtk_action_get_name (action);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	if (g_ascii_strcasecmp (action_name, "ViewToolbar") == 0) {
+		g_object_set (G_OBJECT (priv->toolbar), "visible", visible, NULL);
+
+		if (priv->mode == EOM_WINDOW_MODE_NORMAL)
+			g_settings_set_boolean (priv->ui_settings, EOM_CONF_UI_TOOLBAR, visible);
+
+	} else if (g_ascii_strcasecmp (action_name, "ViewStatusbar") == 0) {
+		g_object_set (G_OBJECT (priv->statusbar), "visible", visible, NULL);
+
+		if (priv->mode == EOM_WINDOW_MODE_NORMAL)
+			g_settings_set_boolean (priv->ui_settings, EOM_CONF_UI_STATUSBAR, visible);
+
+	} else if (g_ascii_strcasecmp (action_name, "ViewImageCollection") == 0) {
+		if (visible) {
+			/* Make sure the focus widget is realized to
+			 * avoid warnings on keypress events */
+			if (!gtk_widget_get_realized (window->priv->thumbview))
+				gtk_widget_realize (window->priv->thumbview);
+
+			gtk_widget_show (priv->nav);
+			gtk_widget_grab_focus (priv->thumbview);
+		} else {
+			/* Make sure the focus widget is realized to
+			 * avoid warnings on keypress events.
+			 * Don't do it during init phase or the view
+			 * will get a bogus allocation. */
+			if (!gtk_widget_get_realized (priv->view)
+			    && priv->status == EOM_WINDOW_STATUS_NORMAL)
+				gtk_widget_realize (priv->view);
+
+			gtk_widget_hide (priv->nav);
+
+			if (gtk_widget_get_realized (priv->view))
+				gtk_widget_grab_focus (priv->view);
+		}
+		g_settings_set_boolean (priv->ui_settings, EOM_CONF_UI_IMAGE_COLLECTION, visible);
+
+	} else if (g_ascii_strcasecmp (action_name, "ViewSidebar") == 0) {
+		if (visible) {
+			gtk_widget_show (priv->sidebar);
+		} else {
+			gtk_widget_hide (priv->sidebar);
+		}
+		g_settings_set_boolean (priv->ui_settings, EOM_CONF_UI_SIDEBAR, visible);
+	}
+}
+
+static void
+wallpaper_info_bar_response (GtkInfoBar *bar, gint response, EomWindow *window)
+{
+	if (response == GTK_RESPONSE_YES) {
+		GAppInfo *app_info;
+		GError *error = NULL;
+
+		app_info = g_app_info_create_from_commandline ("mate-appearance-properties --show-page=background",
+							       "mate-appearance-properties",
+							       G_APP_INFO_CREATE_NONE,
+							       &error);
+
+		if (error != NULL) {
+			g_warning ("%s%s", _("Error launching appearance preferences dialog: "),
+				   error->message);
+			g_error_free (error);
+			error = NULL;
+		}
+
+		if (app_info != NULL) {
+			GdkAppLaunchContext *context;
+			GdkDisplay *display;
+
+			display = gtk_widget_get_display (GTK_WIDGET (window));
+			context = gdk_display_get_app_launch_context (display);
+			g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (context), &error);
+
+			if (error != NULL) {
+				g_warning ("%s%s", _("Error launching appearance preferences dialog: "),
+					   error->message);
+				g_error_free (error);
+				error = NULL;
+			}
+
+			g_object_unref (context);
+			g_object_unref (app_info);
+		}
+	}
+
+	/* Close message area on every response */
+	eom_window_set_message_area (window, NULL);
+}
+
+static void
+eom_window_set_wallpaper (EomWindow *window, const gchar *filename, const gchar *visible_filename)
+{
+	GtkWidget *info_bar;
+	GtkWidget *image;
+	GtkWidget *label;
+	GtkWidget *hbox;
+	gchar *markup;
+	gchar *text;
+	gchar *basename;
+	GSettings *wallpaper_settings;
+
+	wallpaper_settings = g_settings_new (EOM_CONF_BACKGROUND_SCHEMA);
+	g_settings_set_string (wallpaper_settings,
+				 EOM_CONF_BACKGROUND_FILE,
+				 filename);
+	g_object_unref (wallpaper_settings);
+
+	/* I18N: When setting mnemonics for these strings, watch out to not
+	   clash with mnemonics from eom's menubar */
+	info_bar = gtk_info_bar_new_with_buttons (_("_Open Background Preferences"),
+						  GTK_RESPONSE_YES,
+						  C_("MessageArea","Hi_de"),
+						  GTK_RESPONSE_NO, NULL);
+	gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
+				       GTK_MESSAGE_QUESTION);
+
+	image = gtk_image_new_from_icon_name ("dialog-question",
+					  GTK_ICON_SIZE_DIALOG);
+	label = gtk_label_new (NULL);
+
+	if (!visible_filename)
+		basename = g_path_get_basename (filename);
+
+	/* The newline character is currently necessary due to a problem
+	 * with the automatic line break. */
+	text = g_strdup_printf (_("The image \"%s\" has been set as Desktop Background."
+				  "\nWould you like to modify its appearance?"),
+				visible_filename ? visible_filename : basename);
+	markup = g_markup_printf_escaped ("<b>%s</b>", text);
+	gtk_label_set_markup (GTK_LABEL (label), markup);
+	g_free (markup);
+	g_free (text);
+	if (!visible_filename)
+		g_free (basename);
+
+	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
+	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+	gtk_widget_set_halign (image, GTK_ALIGN_START);
+	gtk_widget_set_valign (image, GTK_ALIGN_END);
+	gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+	gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+	gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar))), hbox, TRUE, TRUE, 0);
+	gtk_widget_show_all (hbox);
+	gtk_widget_show (info_bar);
+
+
+	eom_window_set_message_area (window, info_bar);
+	gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar),
+					   GTK_RESPONSE_YES);
+	g_signal_connect (info_bar, "response",
+			  G_CALLBACK (wallpaper_info_bar_response), window);
+}
+
+static void
+eom_job_save_cb (EomJobSave *job, gpointer user_data)
+{
+	EomWindow *window = EOM_WINDOW (user_data);
+	GtkAction *action_save;
+
+	g_signal_handlers_disconnect_by_func (job,
+					      eom_job_save_cb,
+					      window);
+
+	g_signal_handlers_disconnect_by_func (job,
+					      eom_job_save_progress_cb,
+					      window);
+
+	g_object_unref (window->priv->save_job);
+	window->priv->save_job = NULL;
+
+	update_status_bar (window);
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action_save = gtk_action_group_get_action (window->priv->actions_image,
+						   "ImageSave");
+	gtk_action_set_sensitive (action_save, FALSE);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+static void
+eom_job_copy_cb (EomJobCopy *job, gpointer user_data)
+{
+	EomWindow *window = EOM_WINDOW (user_data);
+	gchar *filepath, *basename, *filename, *extension;
+	GtkAction *action;
+	GFile *source_file, *dest_file;
+
+	/* Create source GFile */
+	basename = g_file_get_basename (job->images->data);
+	filepath = g_build_filename (job->dest, basename, NULL);
+	source_file = g_file_new_for_path (filepath);
+	g_free (filepath);
+
+	/* Create destination GFile */
+	extension = eom_util_filename_get_extension (basename);
+	filename = g_strdup_printf  ("%s.%s", EOM_WALLPAPER_FILENAME, extension);
+	filepath = g_build_filename (job->dest, filename, NULL);
+	dest_file = g_file_new_for_path (filepath);
+	g_free (filename);
+	g_free (extension);
+
+	/* Move the file */
+	g_file_move (source_file, dest_file, G_FILE_COPY_OVERWRITE,
+		     NULL, NULL, NULL, NULL);
+
+	/* Set the wallpaper */
+	eom_window_set_wallpaper (window, filepath, basename);
+	g_free (basename);
+	g_free (filepath);
+
+	gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+			   window->priv->copy_file_cid);
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action = gtk_action_group_get_action (window->priv->actions_image,
+					      "ImageSetAsWallpaper");
+	gtk_action_set_sensitive (action, TRUE);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	window->priv->copy_job = NULL;
+
+	g_object_unref (source_file);
+	g_object_unref (dest_file);
+	g_object_unref (G_OBJECT (job->images->data));
+	g_list_free (job->images);
+	g_object_unref (job);
+}
+
+static gboolean
+eom_window_save_images (EomWindow *window, GList *images)
+{
+	EomWindowPrivate *priv;
+
+	priv = window->priv;
+
+	if (window->priv->save_job != NULL)
+		return FALSE;
+
+	priv->save_job = eom_job_save_new (images);
+
+	g_signal_connect (priv->save_job,
+			  "finished",
+			  G_CALLBACK (eom_job_save_cb),
+			  window);
+
+	g_signal_connect (priv->save_job,
+			  "progress",
+			  G_CALLBACK (eom_job_save_progress_cb),
+			  window);
+
+	return TRUE;
+}
+
+static void
+eom_window_cmd_save (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+	EomWindow *window;
+	GList *images;
+
+	window = EOM_WINDOW (user_data);
+	priv = window->priv;
+
+	if (window->priv->save_job != NULL)
+		return;
+
+	images = eom_thumb_view_get_selected_images (EOM_THUMB_VIEW (priv->thumbview));
+
+	if (eom_window_save_images (window, images)) {
+		eom_job_queue_add_job (priv->save_job);
+	}
+}
+
+static GFile*
+eom_window_retrieve_save_as_file (EomWindow *window, EomImage *image)
+{
+	GtkWidget *dialog;
+	GFile *save_file = NULL;
+	GFile *last_dest_folder;
+	gint response;
+
+	g_assert (image != NULL);
+
+	dialog = eom_file_chooser_new (GTK_FILE_CHOOSER_ACTION_SAVE);
+
+	last_dest_folder = window->priv->last_save_as_folder;
+
+	if (last_dest_folder && g_file_query_exists (last_dest_folder, NULL)) {
+		gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (dialog), last_dest_folder, NULL);
+		gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog),
+						 eom_image_get_caption (image));
+	} else {
+		GFile *image_file;
+
+		image_file = eom_image_get_file (image);
+		/* Setting the file will also navigate to its parent folder */
+		gtk_file_chooser_set_file (GTK_FILE_CHOOSER (dialog),
+					   image_file, NULL);
+		g_object_unref (image_file);
+	}
+
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_hide (dialog);
+
+	if (response == GTK_RESPONSE_OK) {
+		save_file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
+		if (window->priv->last_save_as_folder)
+			g_object_unref (window->priv->last_save_as_folder);
+		window->priv->last_save_as_folder = g_file_get_parent (save_file);
+	}
+	gtk_widget_destroy (dialog);
+
+	return save_file;
+}
+
+static void
+eom_window_cmd_save_as (GtkAction *action, gpointer user_data)
+{
+        EomWindowPrivate *priv;
+        EomWindow *window;
+	GList *images;
+	guint n_images;
+
+        window = EOM_WINDOW (user_data);
+	priv = window->priv;
+
+	if (window->priv->save_job != NULL)
+		return;
+
+	images = eom_thumb_view_get_selected_images (EOM_THUMB_VIEW (priv->thumbview));
+	n_images = g_list_length (images);
+
+	if (n_images == 1) {
+		GFile *file;
+
+		file = eom_window_retrieve_save_as_file (window, images->data);
+
+		if (!file) {
+			g_list_free (images);
+			return;
+		}
+
+		priv->save_job = eom_job_save_as_new (images, NULL, file);
+
+		g_object_unref (file);
+	} else if (n_images > 1) {
+		GFile *base_file;
+		GtkWidget *dialog;
+		gchar *basedir;
+		EomURIConverter *converter;
+
+		basedir = g_get_current_dir ();
+		base_file = g_file_new_for_path (basedir);
+		g_free (basedir);
+
+		dialog = eom_save_as_dialog_new (GTK_WINDOW (window),
+						 images,
+						 base_file);
+
+		gtk_widget_show_all (dialog);
+
+		if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) {
+			g_object_unref (base_file);
+			g_list_free (images);
+			gtk_widget_destroy (dialog);
+
+			return;
+		}
+
+		converter = eom_save_as_dialog_get_converter (dialog);
+
+		g_assert (converter != NULL);
+
+		priv->save_job = eom_job_save_as_new (images, converter, NULL);
+
+		gtk_widget_destroy (dialog);
+
+		g_object_unref (converter);
+		g_object_unref (base_file);
+	} else {
+		/* n_images = 0 -- No Image selected */
+		return;
+	}
+
+	g_signal_connect (priv->save_job,
+			  "finished",
+			  G_CALLBACK (eom_job_save_cb),
+			  window);
+
+	g_signal_connect (priv->save_job,
+			  "progress",
+			  G_CALLBACK (eom_job_save_progress_cb),
+			  window);
+
+	eom_job_queue_add_job (priv->save_job);
+}
+
+static void
+eom_window_cmd_open_containing_folder (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+
+	GFile *file;
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	priv = EOM_WINDOW (user_data)->priv;
+
+	g_return_if_fail (priv->image != NULL);
+
+	file = eom_image_get_file (priv->image);
+
+	g_return_if_fail (file != NULL);
+
+	eom_util_show_file_in_filemanager (file,
+	                                   GTK_WINDOW (user_data));
+}
+
+static void
+eom_window_cmd_print (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window = EOM_WINDOW (user_data);
+
+	eom_window_print (window);
+}
+
+/**
+ * eom_window_get_properties_dialog:
+ * @window: a #EomWindow
+ *
+ * Gets the @window property dialog. The widget will be built on the first call to this function.
+ *
+ * Returns: (transfer none): a #GtkDialog.
+ */
+
+GtkWidget*
+eom_window_get_properties_dialog (EomWindow *window)
+{
+	EomWindowPrivate *priv;
+
+	g_return_val_if_fail (EOM_IS_WINDOW (window), NULL);
+
+	priv = window->priv;
+
+	if (priv->properties_dlg == NULL) {
+		GtkAction *next_image_action, *previous_image_action;
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		next_image_action =
+			gtk_action_group_get_action (priv->actions_collection,
+						     "GoNext");
+
+		previous_image_action =
+			gtk_action_group_get_action (priv->actions_collection,
+						     "GoPrevious");
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+		priv->properties_dlg =
+			eom_properties_dialog_new (GTK_WINDOW (window),
+						   EOM_THUMB_VIEW (priv->thumbview),
+						   next_image_action,
+						   previous_image_action);
+
+		eom_properties_dialog_update (EOM_PROPERTIES_DIALOG (priv->properties_dlg),
+					      priv->image);
+		g_settings_bind (priv->ui_settings,
+				 EOM_CONF_UI_PROPSDIALOG_NETBOOK_MODE,
+				 priv->properties_dlg, "netbook-mode",
+				 G_SETTINGS_BIND_GET);
+	}
+
+	return priv->properties_dlg;
+}
+
+static void
+eom_window_cmd_properties (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window = EOM_WINDOW (user_data);
+	GtkWidget *dialog;
+
+	dialog = eom_window_get_properties_dialog (window);
+	gtk_widget_show (dialog);
+}
+
+static void
+eom_window_cmd_undo (GtkAction *action, gpointer user_data)
+{
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	apply_transformation (EOM_WINDOW (user_data), NULL);
+}
+
+static void
+eom_window_cmd_flip_horizontal (GtkAction *action, gpointer user_data)
+{
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	apply_transformation (EOM_WINDOW (user_data),
+			      eom_transform_flip_new (EOM_TRANSFORM_FLIP_HORIZONTAL));
+}
+
+static void
+eom_window_cmd_flip_vertical (GtkAction *action, gpointer user_data)
+{
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	apply_transformation (EOM_WINDOW (user_data),
+			      eom_transform_flip_new (EOM_TRANSFORM_FLIP_VERTICAL));
+}
+
+static void
+eom_window_cmd_rotate_90 (GtkAction *action, gpointer user_data)
+{
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	apply_transformation (EOM_WINDOW (user_data),
+			      eom_transform_rotate_new (90));
+}
+
+static void
+eom_window_cmd_rotate_270 (GtkAction *action, gpointer user_data)
+{
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	apply_transformation (EOM_WINDOW (user_data),
+			      eom_transform_rotate_new (270));
+}
+
+static void
+eom_window_cmd_wallpaper (GtkAction *action, gpointer user_data)<--- Shadowed declaration
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+	EomImage *image;
+	GFile *file;
+	char *filename = NULL;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+	priv = window->priv;
+
+	/* If currently copying an image to set it as wallpaper, return. */
+	if (priv->copy_job != NULL)
+		return;
+
+	image = eom_thumb_view_get_first_selected_image (EOM_THUMB_VIEW (priv->thumbview));
+
+	g_return_if_fail (EOM_IS_IMAGE (image));
+
+	file = eom_image_get_file (image);
+
+	filename = g_file_get_path (file);
+
+	/* Currently only local files can be set as wallpaper */
+	if (filename == NULL || !eom_util_file_is_persistent (file))
+	{
+		GList *files = NULL;
+		GtkAction *action;<--- Shadow variable
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		action = gtk_action_group_get_action (window->priv->actions_image,
+						      "ImageSetAsWallpaper");
+		gtk_action_set_sensitive (action, FALSE);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+
+		priv->copy_file_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (priv->statusbar),
+								    "copy_file_cid");
+		gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar),
+				    priv->copy_file_cid,
+				    _("Saving image locally…"));
+
+		files = g_list_append (files, eom_image_get_file (image));
+		priv->copy_job = eom_job_copy_new (files, g_get_user_data_dir ());
+		g_signal_connect (priv->copy_job,
+				  "finished",
+				  G_CALLBACK (eom_job_copy_cb),
+				  window);
+		g_signal_connect (priv->copy_job,
+				  "progress",
+				  G_CALLBACK (eom_job_progress_cb),
+				  window);
+		eom_job_queue_add_job (priv->copy_job);
+
+		g_object_unref (file);
+		g_free (filename);
+		return;
+	}
+
+	g_object_unref (file);
+
+	eom_window_set_wallpaper (window, filename, NULL);
+
+	g_free (filename);
+}
+
+static gboolean
+eom_window_all_images_trasheable (GList *images)
+{
+	GFile *file;
+	GFileInfo *file_info;
+	GList *iter;
+	EomImage *image;
+	gboolean can_trash = TRUE;
+
+	for (iter = images; iter != NULL; iter = g_list_next (iter)) {
+		image = (EomImage *) iter->data;
+		file = eom_image_get_file (image);
+		file_info = g_file_query_info (file,
+					       G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
+					       0, NULL, NULL);
+		can_trash = g_file_info_get_attribute_boolean (file_info,
+							       G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH);
+
+		g_object_unref (file_info);
+		g_object_unref (file);
+
+		if (can_trash == FALSE)
+			break;
+	}
+
+	return can_trash;
+}
+
+static int
+show_move_to_trash_confirm_dialog (EomWindow *window, GList *images, gboolean can_trash)
+{
+	GtkWidget *dlg;
+	char *prompt;
+	int response;
+	int n_images;
+	EomImage *image;
+	static gboolean dontaskagain = FALSE;
+	gboolean neverask = FALSE;
+	GtkWidget* dontask_cbutton = NULL;
+
+	/* Check if the user never wants to be bugged. */
+	neverask = g_settings_get_boolean (window->priv->ui_settings,
+					 EOM_CONF_UI_DISABLE_TRASH_CONFIRMATION);
+
+	/* Assume agreement, if the user doesn't want to be
+	 * asked and the trash is available */
+	if (can_trash && (dontaskagain || neverask))
+		return GTK_RESPONSE_OK;
+
+	n_images = g_list_length (images);
+
+	if (n_images == 1) {
+		image = EOM_IMAGE (images->data);
+		if (can_trash) {
+			prompt = g_strdup_printf (_("Are you sure you want to move\n\"%s\" to the trash?"),
+						  eom_image_get_caption (image));
+		} else {
+			prompt = g_strdup_printf (_("A trash for \"%s\" couldn't be found. Do you want to remove "
+						    "this image permanently?"), eom_image_get_caption (image));
+		}
+	} else {
+		if (can_trash) {
+			prompt = g_strdup_printf (ngettext("Are you sure you want to move\n"
+							   "the %d selected image to the trash?",
+							   "Are you sure you want to move\n"
+							   "the %d selected images to the trash?", n_images), n_images);
+		} else {
+			prompt = g_strdup (_("Some of the selected images can't be moved to the trash "
+					     "and will be removed permanently. Are you sure you want "
+					     "to proceed?"));
+		}
+	}
+
+	dlg = gtk_message_dialog_new_with_markup (GTK_WINDOW (window),
+						  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+						  GTK_MESSAGE_WARNING,
+						  GTK_BUTTONS_NONE,
+						  "<span weight=\"bold\" size=\"larger\">%s</span>",
+						  prompt);
+	g_free (prompt);
+
+	gtk_dialog_add_button (GTK_DIALOG (dlg), "gtk-cancel", GTK_RESPONSE_CANCEL);
+
+	if (can_trash) {
+		gtk_dialog_add_button (GTK_DIALOG (dlg), _("Move to _Trash"), GTK_RESPONSE_OK);
+
+		dontask_cbutton = gtk_check_button_new_with_mnemonic (_("_Do not ask again during this session"));
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dontask_cbutton), FALSE);
+
+		gtk_box_pack_end (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), dontask_cbutton, TRUE, TRUE, 0);
+	} else {
+		if (n_images == 1) {
+			gtk_dialog_add_button (GTK_DIALOG (dlg), "gtk-delete", GTK_RESPONSE_OK);
+		} else {
+			gtk_dialog_add_button (GTK_DIALOG (dlg), "gtk-yes", GTK_RESPONSE_OK);
+		}
+	}
+
+	gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
+	gtk_window_set_title (GTK_WINDOW (dlg), "");
+	gtk_widget_show_all (dlg);
+
+	response = gtk_dialog_run (GTK_DIALOG (dlg));
+
+	/* Only update the property if the user has accepted */
+	if (can_trash && response == GTK_RESPONSE_OK)
+		dontaskagain = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dontask_cbutton));
+
+	/* The checkbutton is destroyed together with the dialog */
+	gtk_widget_destroy (dlg);
+
+	return response;
+}
+
+static gboolean
+move_to_trash_real (EomImage *image, GError **error)
+{
+	GFile *file;
+	GFileInfo *file_info;
+	gboolean can_trash, result;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (image), FALSE);
+
+	file = eom_image_get_file (image);
+	file_info = g_file_query_info (file,
+				       G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
+				       0, NULL, NULL);
+	if (file_info == NULL) {
+		g_set_error (error,
+			     EOM_WINDOW_ERROR,
+			     EOM_WINDOW_ERROR_TRASH_NOT_FOUND,
+			     _("Couldn't access trash."));
+		return FALSE;
+	}
+
+	can_trash = g_file_info_get_attribute_boolean (file_info,
+						       G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH);
+	g_object_unref (file_info);
+	if (can_trash)
+	{
+		result = g_file_trash (file, NULL, NULL);
+		if (result == FALSE) {
+			g_set_error (error,
+				     EOM_WINDOW_ERROR,
+				     EOM_WINDOW_ERROR_TRASH_NOT_FOUND,
+				     _("Couldn't access trash."));
+		}
+	} else {
+		result = g_file_delete (file, NULL, NULL);
+		if (result == FALSE) {
+			g_set_error (error,
+				     EOM_WINDOW_ERROR,
+				     EOM_WINDOW_ERROR_IO,
+				     _("Couldn't delete file"));
+		}
+	}
+
+        g_object_unref (file);
+
+	return result;
+}
+
+static void
+eom_window_cmd_copy_image (GtkAction *action, gpointer user_data)
+{
+	GtkClipboard *clipboard;
+	EomWindow *window;
+	EomWindowPrivate *priv;
+	EomImage *image;
+	EomClipboardHandler *cbhandler;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+	priv = window->priv;
+
+	image = eom_thumb_view_get_first_selected_image (EOM_THUMB_VIEW (priv->thumbview));
+
+	g_return_if_fail (EOM_IS_IMAGE (image));
+
+	clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+
+	cbhandler = eom_clipboard_handler_new (image);
+	// cbhandler will self-destruct when it's not needed anymore
+	eom_clipboard_handler_copy_to_clipboard (cbhandler, clipboard);
+
+}
+
+static void
+eom_window_cmd_move_to_trash (GtkAction *action, gpointer user_data)
+{
+	GList *images;
+	GList *it;
+	EomWindowPrivate *priv;
+	EomListStore *list;
+	int pos;
+	EomImage *img;
+	EomWindow *window;
+	int response;
+	int n_images;
+	gboolean success;
+	gboolean can_trash;
+	const gchar *action_name;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	window = EOM_WINDOW (user_data);
+	priv = window->priv;
+	list = priv->store;
+
+	n_images = eom_thumb_view_get_n_selected (EOM_THUMB_VIEW (priv->thumbview));
+
+	if (n_images < 1) return;
+
+	/* save position of selected image after the deletion */
+	images = eom_thumb_view_get_selected_images (EOM_THUMB_VIEW (priv->thumbview));
+
+	g_assert (images != NULL);
+
+	/* HACK: eom_list_store_get_n_selected return list in reverse order */
+	images = g_list_reverse (images);
+
+	can_trash = eom_window_all_images_trasheable (images);
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action_name = gtk_action_get_name (action);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	if (g_ascii_strcasecmp (action_name, "Delete") == 0 ||
+	    can_trash == FALSE) {
+		response = show_move_to_trash_confirm_dialog (window, images, can_trash);
+
+		if (response != GTK_RESPONSE_OK) return;
+	}
+
+	pos = eom_list_store_get_pos_by_image (list, EOM_IMAGE (images->data));
+
+	/* FIXME: make a nice progress dialog */
+	/* Do the work actually. First try to delete the image from the disk. If this
+	 * is successful, remove it from the screen. Otherwise show error dialog.
+	 */
+	for (it = images; it != NULL; it = it->next) {
+		GError *error = NULL;
+		EomImage *image;
+
+		image = EOM_IMAGE (it->data);
+
+		success = move_to_trash_real (image, &error);
+
+		if (success) {
+			eom_list_store_remove_image (list, image);
+		} else {
+			char *header;
+			GtkWidget *dlg;
+
+			header = g_strdup_printf (_("Error on deleting image %s"),
+						  eom_image_get_caption (image));
+
+			dlg = gtk_message_dialog_new (GTK_WINDOW (window),
+						      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+						      GTK_MESSAGE_ERROR,
+						      GTK_BUTTONS_OK,
+						      "%s", header);
+
+			gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg),
+								  "%s", error->message);
+
+			gtk_dialog_run (GTK_DIALOG (dlg));
+
+			gtk_widget_destroy (dlg);
+
+			g_free (header);
+		}
+	}
+
+	/* free list */
+	g_list_free_full (images, g_object_unref);
+
+	/* select image at previously saved position */
+	pos = MIN (pos, eom_list_store_length (list) - 1);
+
+	if (pos >= 0) {
+		img = eom_list_store_get_image_by_pos (list, pos);
+
+		eom_thumb_view_set_current_image (EOM_THUMB_VIEW (priv->thumbview),
+						  img,
+						  TRUE);
+
+		if (img != NULL) {
+			g_object_unref (img);
+		}
+	}
+}
+
+static void
+eom_window_cmd_fullscreen (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window;
+	gboolean fullscreen;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	window = EOM_WINDOW (user_data);
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	fullscreen = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	if (fullscreen) {
+		eom_window_run_fullscreen (window, FALSE);
+	} else {
+		eom_window_stop_fullscreen (window, FALSE);
+	}
+}
+
+static void
+eom_window_cmd_slideshow (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window;
+	gboolean slideshow;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	window = EOM_WINDOW (user_data);
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	slideshow = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	if (slideshow) {
+		eom_window_run_fullscreen (window, TRUE);
+	} else {
+		eom_window_stop_fullscreen (window, TRUE);
+	}
+}
+
+static void
+eom_window_cmd_pause_slideshow (GtkAction *action, gpointer user_data)
+{
+	EomWindow *window;
+	gboolean slideshow;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	window = EOM_WINDOW (user_data);
+
+	slideshow = window->priv->mode == EOM_WINDOW_MODE_SLIDESHOW;
+
+	if (!slideshow && window->priv->mode != EOM_WINDOW_MODE_FULLSCREEN)
+		return;
+
+	eom_window_run_fullscreen (window, !slideshow);
+}
+
+static void
+eom_window_cmd_zoom_in (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = EOM_WINDOW (user_data)->priv;
+
+	if (priv->view) {
+		eom_scroll_view_zoom_in (EOM_SCROLL_VIEW (priv->view), FALSE);
+	}
+}
+
+static void
+eom_window_cmd_zoom_out (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = EOM_WINDOW (user_data)->priv;
+
+	if (priv->view) {
+		eom_scroll_view_zoom_out (EOM_SCROLL_VIEW (priv->view), FALSE);
+	}
+}
+
+static void
+eom_window_cmd_zoom_normal (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = EOM_WINDOW (user_data)->priv;
+
+	if (priv->view) {
+		eom_scroll_view_set_zoom (EOM_SCROLL_VIEW (priv->view), 1.0);
+	}
+}
+
+static void
+eom_window_cmd_zoom_fit (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = EOM_WINDOW (user_data)->priv;
+
+	if (priv->view) {
+		eom_scroll_view_zoom_fit (EOM_SCROLL_VIEW (priv->view));
+	}
+}
+
+static void
+eom_window_cmd_go_prev (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = EOM_WINDOW (user_data)->priv;
+
+	eom_thumb_view_select_single (EOM_THUMB_VIEW (priv->thumbview),
+				      EOM_THUMB_VIEW_SELECT_LEFT);
+}
+
+static void
+eom_window_cmd_go_next (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = EOM_WINDOW (user_data)->priv;
+
+	eom_thumb_view_select_single (EOM_THUMB_VIEW (priv->thumbview),
+				      EOM_THUMB_VIEW_SELECT_RIGHT);
+}
+
+static void
+eom_window_cmd_go_first (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = EOM_WINDOW (user_data)->priv;
+
+	eom_thumb_view_select_single (EOM_THUMB_VIEW (priv->thumbview),
+				      EOM_THUMB_VIEW_SELECT_FIRST);
+}
+
+static void
+eom_window_cmd_go_last (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = EOM_WINDOW (user_data)->priv;
+
+	eom_thumb_view_select_single (EOM_THUMB_VIEW (priv->thumbview),
+				      EOM_THUMB_VIEW_SELECT_LAST);
+}
+
+static void
+eom_window_cmd_go_random (GtkAction *action, gpointer user_data)
+{
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (user_data));
+
+	eom_debug (DEBUG_WINDOW);
+
+	priv = EOM_WINDOW (user_data)->priv;
+
+	eom_thumb_view_select_single (EOM_THUMB_VIEW (priv->thumbview),
+				      EOM_THUMB_VIEW_SELECT_RANDOM);
+}
+
+static const GtkActionEntry action_entries_window[] = {
+	{ "Image", NULL, N_("_Image") },
+	{ "Edit",  NULL, N_("_Edit") },
+	{ "View",  NULL, N_("_View") },
+	{ "Go",    NULL, N_("_Go") },
+	{ "Tools", NULL, N_("_Tools") },
+	{ "Help",  NULL, N_("_Help") },
+
+	{ "ImageOpen", "document-open",  N_("_Open…"), "<control>O",
+	  N_("Open a file"),
+	  G_CALLBACK (eom_window_cmd_file_open) },
+	{ "ImageClose", "window-close", N_("_Close"), "<control>W",
+	  N_("Close window"),
+	  G_CALLBACK (eom_window_cmd_close_window) },
+	{ "EditToolbar", NULL, N_("T_oolbar"), NULL,
+	  N_("Edit the application toolbar"),
+	  G_CALLBACK (eom_window_cmd_edit_toolbar) },
+	{ "EditPreferences", "preferences-desktop", N_("Prefere_nces"), NULL,
+	  N_("Preferences for Eye of MATE"),
+	  G_CALLBACK (eom_window_cmd_preferences) },
+	{ "HelpManual", "help-browser", N_("_Contents"), "F1",
+	  N_("Help on this application"),
+	  G_CALLBACK (eom_window_cmd_help) },
+	{ "HelpAbout", "help-about", N_("_About"), NULL,
+	  N_("About this application"),
+	  G_CALLBACK (eom_window_cmd_about) }
+};
+
+static const GtkToggleActionEntry toggle_entries_window[] = {
+	{ "ViewToolbar", NULL, N_("_Toolbar"), NULL,
+	  N_("Changes the visibility of the toolbar in the current window"),
+	  G_CALLBACK (eom_window_cmd_show_hide_bar), TRUE },
+	{ "ViewStatusbar", NULL, N_("_Statusbar"), NULL,
+	  N_("Changes the visibility of the statusbar in the current window"),
+	  G_CALLBACK (eom_window_cmd_show_hide_bar), TRUE },
+	{ "ViewImageCollection", "eom-image-collection", N_("_Image Collection"), "<control>F9",
+	  N_("Changes the visibility of the image collection pane in the current window"),
+	  G_CALLBACK (eom_window_cmd_show_hide_bar), TRUE },
+	{ "ViewSidebar", NULL, N_("Side _Pane"), "F9",
+	  N_("Changes the visibility of the side pane in the current window"),
+	  G_CALLBACK (eom_window_cmd_show_hide_bar), TRUE },
+};
+
+static const GtkActionEntry action_entries_image[] = {
+	{ "ImageSave", "document-save", N_("_Save"), "<control>s",
+	  N_("Save changes in currently selected images"),
+	  G_CALLBACK (eom_window_cmd_save) },
+	{ "ImageOpenWith", NULL, N_("Open _with"), NULL,
+	  N_("Open the selected image with a different application"),
+	  NULL},
+	{ "ImageSaveAs", "document-save-as", N_("Save _As…"), "<control><shift>s",
+	  N_("Save the selected images with a different name"),
+	  G_CALLBACK (eom_window_cmd_save_as) },
+	{ "ImageOpenContainingFolder", "folder", N_("Open Containing _Folder"), NULL,
+	  N_("Show the folder which contains this file in the file manager"),
+	  G_CALLBACK (eom_window_cmd_open_containing_folder) },
+	{ "ImagePrint", "document-print", N_("_Print…"), "<control>p",
+	  N_("Print the selected image"),
+	  G_CALLBACK (eom_window_cmd_print) },
+	{ "ImageProperties", "document-properties", N_("Prope_rties"), "<alt>Return",
+	  N_("Show the properties and metadata of the selected image"),
+	  G_CALLBACK (eom_window_cmd_properties) },
+	{ "EditUndo", "edit-undo", N_("_Undo"), "<control>z",
+	  N_("Undo the last change in the image"),
+	  G_CALLBACK (eom_window_cmd_undo) },
+	{ "EditFlipHorizontal", "object-flip-horizontal", N_("Flip _Horizontal"), NULL,
+	  N_("Mirror the image horizontally"),
+	  G_CALLBACK (eom_window_cmd_flip_horizontal) },
+	{ "EditFlipVertical", "object-flip-vertical", N_("Flip _Vertical"), NULL,
+	  N_("Mirror the image vertically"),
+	  G_CALLBACK (eom_window_cmd_flip_vertical) },
+	{ "EditRotate90",  "object-rotate-right",  N_("_Rotate Clockwise"), "<control>r",
+	  N_("Rotate the image 90 degrees to the right"),
+	  G_CALLBACK (eom_window_cmd_rotate_90) },
+	{ "EditRotate270", "object-rotate-left", N_("Rotate Counterc_lockwise"), "<ctrl><shift>r",
+	  N_("Rotate the image 90 degrees to the left"),
+	  G_CALLBACK (eom_window_cmd_rotate_270) },
+	{ "ImageSetAsWallpaper", NULL, N_("Set as _Desktop Background"),
+	  "<control>F8", N_("Set the selected image as the desktop background"),
+	  G_CALLBACK (eom_window_cmd_wallpaper) },
+	{ "EditMoveToTrash", "user-trash", N_("Move to _Trash"), NULL,
+	  N_("Move the selected image to the trash folder"),
+	  G_CALLBACK (eom_window_cmd_move_to_trash) },
+	{ "EditCopyImage", "edit-copy", N_("_Copy"), "<control>C",
+	  N_("Copy the selected image to the clipboard"),
+	  G_CALLBACK (eom_window_cmd_copy_image) },
+	{ "ViewZoomIn", "zoom-in", N_("_Zoom In"), "<control>plus",
+	  N_("Enlarge the image"),
+	  G_CALLBACK (eom_window_cmd_zoom_in) },
+	{ "ViewZoomOut", "zoom-out", N_("Zoom _Out"), "<control>minus",
+	  N_("Shrink the image"),
+	  G_CALLBACK (eom_window_cmd_zoom_out) },
+	{ "ViewZoomNormal", "zoom-original", N_("_Normal Size"), "<control>0",
+	  N_("Show the image at its normal size"),
+	  G_CALLBACK (eom_window_cmd_zoom_normal) },
+	{ "ViewZoomFit", "zoom-fit-best", N_("_Best Fit"), "F",
+	  N_("Fit the image to the window"),
+	  G_CALLBACK (eom_window_cmd_zoom_fit) },
+	{ "ControlEqual", "zoom-in", N_("_Zoom In"), "<control>equal",
+	  N_("Enlarge the image"),
+	  G_CALLBACK (eom_window_cmd_zoom_in) },
+	{ "ControlKpAdd", "zoom-in", N_("_Zoom In"), "<control>KP_Add",
+	  N_("Shrink the image"),
+	  G_CALLBACK (eom_window_cmd_zoom_in) },
+	{ "ControlKpSub", "zoom-out", N_("Zoom _Out"), "<control>KP_Subtract",
+	  N_("Shrink the image"),
+	  G_CALLBACK (eom_window_cmd_zoom_out) },
+	{ "Delete", NULL, N_("Move to _Trash"), "Delete",
+	  NULL,
+	  G_CALLBACK (eom_window_cmd_move_to_trash) },
+};
+
+static const GtkToggleActionEntry toggle_entries_image[] = {
+	{ "ViewFullscreen", "view-fullscreen", N_("_Fullscreen"), "F11",
+	  N_("Show the current image in fullscreen mode"),
+	  G_CALLBACK (eom_window_cmd_fullscreen), FALSE },
+	{ "PauseSlideshow", "media-playback-pause", N_("Pause Slideshow"),
+	  NULL, N_("Pause or resume the slideshow"),
+	  G_CALLBACK (eom_window_cmd_pause_slideshow), FALSE },
+};
+
+static const GtkActionEntry action_entries_collection[] = {
+	{ "GoPrevious", "go-previous", N_("_Previous Image"), "<Alt>Left",
+	  N_("Go to the previous image of the collection"),
+	  G_CALLBACK (eom_window_cmd_go_prev) },
+	{ "GoNext", "go-next", N_("_Next Image"), "<Alt>Right",
+	  N_("Go to the next image of the collection"),
+	  G_CALLBACK (eom_window_cmd_go_next) },
+	{ "GoFirst", "go-first", N_("_First Image"), "<Alt>Home",
+	  N_("Go to the first image of the collection"),
+	  G_CALLBACK (eom_window_cmd_go_first) },
+	{ "GoLast", "go-last", N_("_Last Image"), "<Alt>End",
+	  N_("Go to the last image of the collection"),
+	  G_CALLBACK (eom_window_cmd_go_last) },
+	{ "GoRandom", NULL, N_("_Random Image"), "<control>M",
+	  N_("Go to a random image of the collection"),
+	  G_CALLBACK (eom_window_cmd_go_random) },
+	{ "BackSpace", NULL, N_("_Previous Image"), "BackSpace",
+	  NULL,
+	  G_CALLBACK (eom_window_cmd_go_prev) },
+	{ "Home", NULL, N_("_First Image"), "Home",
+	  NULL,
+	  G_CALLBACK (eom_window_cmd_go_first) },
+	{ "End", NULL, N_("_Last Image"), "End",
+	  NULL,
+	  G_CALLBACK (eom_window_cmd_go_last) },
+};
+
+static const GtkToggleActionEntry toggle_entries_collection[] = {
+	{ "ViewSlideshow", "slideshow-play", N_("S_lideshow"), "F5",
+	  N_("Start a slideshow view of the images"),
+	  G_CALLBACK (eom_window_cmd_slideshow), FALSE },
+};
+
+static void
+menu_item_select_cb (GtkMenuItem *proxy, EomWindow *window)
+{
+	GtkAction *action;
+	char *message;
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (proxy));
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	g_return_if_fail (action != NULL);
+
+	g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
+
+	if (message) {
+		gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
+				    window->priv->tip_message_cid, message);
+		g_free (message);
+	}
+}
+
+static void
+menu_item_deselect_cb (GtkMenuItem *proxy, EomWindow *window)
+{
+	gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+			   window->priv->tip_message_cid);
+}
+
+static void
+connect_proxy_cb (GtkUIManager *manager,
+                  GtkAction *action,
+                  GtkWidget *proxy,
+                  EomWindow *window)
+{
+	if (GTK_IS_MENU_ITEM (proxy)) {
+		disconnect_proxy_cb (manager, action, proxy, window);
+		g_signal_connect (proxy, "select",
+				  G_CALLBACK (menu_item_select_cb), window);
+		g_signal_connect (proxy, "deselect",
+				  G_CALLBACK (menu_item_deselect_cb), window);
+	}
+}
+
+static void
+disconnect_proxy_cb (GtkUIManager *manager,
+                     GtkAction *action,
+                     GtkWidget *proxy,
+                     EomWindow *window)
+{
+	if (GTK_IS_MENU_ITEM (proxy)) {
+		g_signal_handlers_disconnect_by_func
+			(proxy, G_CALLBACK (menu_item_select_cb), window);
+		g_signal_handlers_disconnect_by_func
+			(proxy, G_CALLBACK (menu_item_deselect_cb), window);
+	}
+}
+
+static void
+set_action_properties (GtkActionGroup *window_group,
+		       GtkActionGroup *image_group,
+		       GtkActionGroup *collection_group)
+{
+        GtkAction *action;
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+        action = gtk_action_group_get_action (collection_group, "GoPrevious");
+        g_object_set (action, "short_label", _("Previous"), NULL);
+        g_object_set (action, "is-important", TRUE, NULL);
+
+        action = gtk_action_group_get_action (collection_group, "GoNext");
+        g_object_set (action, "short_label", _("Next"), NULL);
+        g_object_set (action, "is-important", TRUE, NULL);
+
+        action = gtk_action_group_get_action (image_group, "EditRotate90");
+        g_object_set (action, "short_label", _("Right"), NULL);
+
+        action = gtk_action_group_get_action (image_group, "EditRotate270");
+        g_object_set (action, "short_label", _("Left"), NULL);
+
+        action = gtk_action_group_get_action (image_group, "ImageOpenContainingFolder");
+        g_object_set (action, "short_label", _("Open Folder"), NULL);
+
+        action = gtk_action_group_get_action (image_group, "ViewZoomIn");
+        g_object_set (action, "short_label", _("In"), NULL);
+
+        action = gtk_action_group_get_action (image_group, "ViewZoomOut");
+        g_object_set (action, "short_label", _("Out"), NULL);
+
+        action = gtk_action_group_get_action (image_group, "ViewZoomNormal");
+        g_object_set (action, "short_label", _("Normal"), NULL);
+
+        action = gtk_action_group_get_action (image_group, "ViewZoomFit");
+        g_object_set (action, "short_label", _("Fit"), NULL);
+
+        action = gtk_action_group_get_action (window_group, "ViewImageCollection");
+        g_object_set (action, "short_label", _("Collection"), NULL);
+
+        action = gtk_action_group_get_action (image_group, "EditMoveToTrash");
+        g_object_set (action, "short_label", C_("action (to trash)", "Trash"), NULL);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+static gint
+sort_recents_mru (GtkRecentInfo *a, GtkRecentInfo *b)
+{
+	gboolean has_eom_a, has_eom_b;
+
+	/* We need to check this first as gtk_recent_info_get_application_info
+	 * will treat it as a non-fatal error when the GtkRecentInfo doesn't
+	 * have the application registered. */
+	has_eom_a = gtk_recent_info_has_application (a,
+						     EOM_RECENT_FILES_APP_NAME);
+	has_eom_b = gtk_recent_info_has_application (b,
+						     EOM_RECENT_FILES_APP_NAME);
+	if (has_eom_a && has_eom_b) {
+		time_t time_a, time_b;
+
+		/* These should not fail as we already checked that
+		 * the application is registered with the info objects */
+		gtk_recent_info_get_application_info (a,
+						      EOM_RECENT_FILES_APP_NAME,
+						      NULL,
+						      NULL,
+						      &time_a);
+		gtk_recent_info_get_application_info (b,
+						      EOM_RECENT_FILES_APP_NAME,
+						      NULL,
+						      NULL,
+						      &time_b);
+
+		return (time_b - time_a);
+	} else if (has_eom_a) {
+		return -1;
+	} else if (has_eom_b) {
+		return 1;
+	}
+
+	return 0;
+}
+
+static void
+eom_window_update_recent_files_menu (EomWindow *window)
+{
+	EomWindowPrivate *priv;
+	GList *actions = NULL, *li = NULL, *items = NULL;
+	guint count_recent = 0;
+
+	priv = window->priv;
+
+	if (priv->recent_menu_id != 0)
+		gtk_ui_manager_remove_ui (priv->ui_mgr, priv->recent_menu_id);
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	actions = gtk_action_group_list_actions (priv->actions_recent);
+
+	for (li = actions; li != NULL; li = li->next) {
+		g_signal_handlers_disconnect_by_func (GTK_ACTION (li->data),
+						      G_CALLBACK(eom_window_open_recent_cb),
+						      window);
+
+		gtk_action_group_remove_action (priv->actions_recent,
+						GTK_ACTION (li->data));
+	}
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	g_list_free (actions);
+
+	priv->recent_menu_id = gtk_ui_manager_new_merge_id (priv->ui_mgr);
+	items = gtk_recent_manager_get_items (gtk_recent_manager_get_default());
+	items = g_list_sort (items, (GCompareFunc) sort_recents_mru);
+
+	for (li = items; li != NULL && count_recent < EOM_RECENT_FILES_LIMIT; li = li->next) {
+		gchar *action_name;
+		gchar *label;
+		gchar *tip;
+		gchar **display_name;
+		gchar *label_filename;
+		GtkAction *action;
+		GtkRecentInfo *info = li->data;
+
+		/* Sorting moves non-EOM files to the end of the list.
+		 * So no file of interest will follow if this test fails */
+		if (!gtk_recent_info_has_application (info, EOM_RECENT_FILES_APP_NAME))
+			break;
+
+		count_recent++;
+
+		action_name = g_strdup_printf ("recent-info-%d", count_recent);
+		display_name = g_strsplit (gtk_recent_info_get_display_name (info), "_", -1);
+		label_filename = g_strjoinv ("__", display_name);
+		label = g_strdup_printf ("%s_%d. %s",
+				(is_rtl ? "\xE2\x80\x8F" : ""), count_recent, label_filename);
+		g_free (label_filename);
+		g_strfreev (display_name);
+
+		tip = gtk_recent_info_get_uri_display (info);
+
+		/* This is a workaround for a bug (#351945) regarding
+		 * gtk_recent_info_get_uri_display() and remote URIs.
+		 * mate_vfs_format_uri_for_display is sufficient here
+		 * since the password gets stripped when adding the
+		 * file to the recently used list. */
+		if (tip == NULL)
+			tip = g_uri_unescape_string (gtk_recent_info_get_uri (info), NULL);
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		action = gtk_action_new (action_name, label, tip, NULL);
+		gtk_action_set_always_show_image (action, TRUE);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+
+		g_object_set_data_full (G_OBJECT (action), "gtk-recent-info",
+					gtk_recent_info_ref (info),
+					(GDestroyNotify) gtk_recent_info_unref);
+
+		g_object_set (G_OBJECT (action), "icon-name", "image-x-generic", NULL);
+
+		g_signal_connect (action, "activate",
+				  G_CALLBACK (eom_window_open_recent_cb),
+				  window);
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		gtk_action_group_add_action (priv->actions_recent, action);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+
+		g_object_unref (action);
+
+		gtk_ui_manager_add_ui (priv->ui_mgr, priv->recent_menu_id,
+				       "/MainMenu/Image/RecentDocuments",
+				       action_name, action_name,
+				       GTK_UI_MANAGER_AUTO, FALSE);
+
+		g_free (action_name);
+		g_free (label);
+		g_free (tip);
+	}
+
+	g_list_free_full (items, (GDestroyNotify) gtk_recent_info_unref);
+}
+
+static void
+eom_window_recent_manager_changed_cb (GtkRecentManager *manager, EomWindow *window)
+{
+	eom_window_update_recent_files_menu (window);
+}
+
+static void
+eom_window_drag_data_received (GtkWidget *widget,
+                               GdkDragContext *context,
+                               gint x, gint y,
+                               GtkSelectionData *selection_data,
+                               guint info, guint time)
+{
+	GSList *file_list;
+	EomWindow *window;
+	GdkAtom target;
+	GtkWidget *src;
+
+	target = gtk_selection_data_get_target (selection_data);
+
+	if (!gtk_targets_include_uri (&target, 1))
+		return;
+
+	/* if the request is from another process this will return NULL */
+	src = gtk_drag_get_source_widget (context);
+
+	/* if the drag request originates from the current eom instance, ignore
+	   the request if the source window is the same as the dest window */
+	if (src &&
+	    gtk_widget_get_toplevel (src) == gtk_widget_get_toplevel (widget))
+	{
+		gdk_drag_status (context, 0, time);
+		return;
+	}
+
+	if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_COPY) {
+		window = EOM_WINDOW (widget);
+
+		file_list = eom_util_parse_uri_string_list_to_file_list ((const gchar *) gtk_selection_data_get_data (selection_data));
+
+		eom_window_open_file_list (window, file_list);
+	}
+}
+
+static void
+eom_window_set_drag_dest (EomWindow *window)
+{
+	gtk_drag_dest_set (GTK_WIDGET (window),
+                           GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
+                           NULL, 0,
+                           GDK_ACTION_COPY | GDK_ACTION_ASK);
+	gtk_drag_dest_add_uri_targets (GTK_WIDGET (window));
+}
+
+static void
+eom_window_sidebar_visibility_changed (GtkWidget *widget, EomWindow *window)
+{
+	GtkAction *action;
+	gboolean visible;
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	visible = gtk_widget_get_visible (window->priv->sidebar);
+
+	action = gtk_action_group_get_action (window->priv->actions_window,
+					      "ViewSidebar");
+
+	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
+		gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	/* Focus the image */
+	if (!visible && window->priv->image != NULL)
+		gtk_widget_grab_focus (window->priv->view);
+}
+
+static void
+eom_window_sidebar_page_added (EomSidebar  *sidebar,
+			       GtkWidget   *main_widget,
+			       EomWindow   *window)
+{
+	if (eom_sidebar_get_n_pages (sidebar) == 1) {
+		GtkAction *action;
+		gboolean show;
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		action = gtk_action_group_get_action (window->priv->actions_window,
+						      "ViewSidebar");
+
+		gtk_action_set_sensitive (action, TRUE);
+
+		show = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+
+		if (show)
+			gtk_widget_show (GTK_WIDGET (sidebar));
+	}
+}
+static void
+eom_window_sidebar_page_removed (EomSidebar  *sidebar,
+			         GtkWidget   *main_widget,
+			         EomWindow   *window)
+{
+	if (eom_sidebar_is_empty (sidebar)) {
+		GtkAction *action;
+
+		gtk_widget_hide (GTK_WIDGET (sidebar));
+
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+		action = gtk_action_group_get_action (window->priv->actions_window,
+						      "ViewSidebar");
+
+		gtk_action_set_sensitive (action, FALSE);
+		G_GNUC_END_IGNORE_DEPRECATIONS;
+	}
+}
+
+static void
+eom_window_finish_saving (EomWindow *window)
+{
+	EomWindowPrivate *priv = window->priv;
+
+	gtk_widget_set_sensitive (GTK_WIDGET (window), FALSE);
+
+	do {
+		gtk_main_iteration ();
+	} while (priv->save_job != NULL);
+}
+
+static GAppInfo *
+get_appinfo_for_editor (EomWindow *window)
+{
+	/* We want this function to always return the same thing, not
+	 * just for performance reasons, but because if someone edits
+	 * GConf while eom is running, the application could get into an
+	 * inconsistent state.  If the editor exists once, it gets added
+	 * to the "available" list of the EggToolbarsModel (for which
+	 * there is no API to remove it).  If later the editor no longer
+	 * existed when constructing a new window, we'd be unable to
+	 * construct a GtkAction for the editor for that window, causing
+	 * assertion failures when viewing the "Edit Toolbars" dialog
+	 * (item is available, but can't find the GtkAction for it).
+	 *
+	 * By ensuring we keep the GAppInfo around, we avoid the
+	 * possibility of that situation occurring.
+	 */
+	static GDesktopAppInfo *app_info = NULL;
+	static gboolean initialised;
+
+	if (!initialised) {
+		gchar *editor;
+
+		editor = g_settings_get_string (window->priv->ui_settings,
+		                                EOM_CONF_UI_EXTERNAL_EDITOR);
+
+		if (editor != NULL) {
+			app_info = g_desktop_app_info_new (editor);
+		}
+
+		initialised = TRUE;
+		g_free (editor);
+	}
+
+	return (GAppInfo *) app_info;
+}
+
+static void
+eom_window_open_editor (GtkAction *action,
+                        EomWindow *window)
+{
+	GdkAppLaunchContext *context;
+	GAppInfo *app_info;
+	GList files;
+
+	app_info = get_appinfo_for_editor (window);
+
+	if (app_info == NULL)
+		return;
+
+	context = gdk_display_get_app_launch_context (
+	  gtk_widget_get_display (GTK_WIDGET (window)));
+	gdk_app_launch_context_set_screen (context,
+	  gtk_widget_get_screen (GTK_WIDGET (window)));
+	gdk_app_launch_context_set_icon (context,
+	  g_app_info_get_icon (app_info));
+	gdk_app_launch_context_set_timestamp (context,
+	  gtk_get_current_event_time ());
+
+	{
+		GList f = { eom_image_get_file (window->priv->image) };
+		files = f;
+	}
+
+	g_app_info_launch (app_info, &files,
+                           G_APP_LAUNCH_CONTEXT (context), NULL);
+
+	g_object_unref (files.data);
+	g_object_unref (context);
+}
+
+static void
+eom_window_add_open_editor_action (EomWindow *window)
+{
+	EggToolbarsModel *model;
+	GAppInfo *app_info;
+	GtkAction *action;
+        gchar *tooltip;
+
+	app_info = get_appinfo_for_editor (window);
+
+	if (app_info == NULL)
+		return;
+
+	model = eom_application_get_toolbars_model (EOM_APP);
+	egg_toolbars_model_set_name_flags (model, "OpenEditor",
+	                                   EGG_TB_MODEL_NAME_KNOWN);
+
+	tooltip = g_strdup_printf (_("Edit the current image using %s"),
+	                           g_app_info_get_name (app_info));
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	action = gtk_action_new ("OpenEditor", _("Edit Image"), tooltip, NULL);
+	gtk_action_set_gicon (action, g_app_info_get_icon (app_info));
+	gtk_action_set_is_important (action, TRUE);
+
+	g_signal_connect (action, "activate",
+	                  G_CALLBACK (eom_window_open_editor), window);
+
+	gtk_action_group_add_action (window->priv->actions_image, action);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	g_object_unref (action);
+	g_free (tooltip);
+}
+
+static void
+eom_window_construct_ui (EomWindow *window)
+{
+	EomWindowPrivate *priv;
+
+	GError *error = NULL;
+
+	GtkWidget *menubar;
+	GtkWidget *thumb_popup;
+	GtkWidget *view_popup;
+	GtkWidget *hpaned;
+	GtkWidget *menuitem;
+
+	g_return_if_fail (EOM_IS_WINDOW (window));
+
+	priv = window->priv;
+
+	priv->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+	gtk_container_add (GTK_CONTAINER (window), priv->box);
+	gtk_widget_show (priv->box);
+
+	priv->ui_mgr = gtk_ui_manager_new ();
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	priv->actions_window = gtk_action_group_new ("MenuActionsWindow");
+
+	gtk_action_group_set_translation_domain (priv->actions_window,
+						 GETTEXT_PACKAGE);
+
+	gtk_action_group_add_actions (priv->actions_window,
+				      action_entries_window,
+				      G_N_ELEMENTS (action_entries_window),
+				      window);
+
+	gtk_action_group_add_toggle_actions (priv->actions_window,
+					     toggle_entries_window,
+					     G_N_ELEMENTS (toggle_entries_window),
+					     window);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	gtk_ui_manager_insert_action_group (priv->ui_mgr, priv->actions_window, 0);
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	priv->actions_image = gtk_action_group_new ("MenuActionsImage");
+	gtk_action_group_set_translation_domain (priv->actions_image,
+						 GETTEXT_PACKAGE);
+
+	gtk_action_group_add_actions (priv->actions_image,
+				      action_entries_image,
+				      G_N_ELEMENTS (action_entries_image),
+				      window);
+
+	eom_window_add_open_editor_action (window);
+
+	gtk_action_group_add_toggle_actions (priv->actions_image,
+					     toggle_entries_image,
+					     G_N_ELEMENTS (toggle_entries_image),
+					     window);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	gtk_ui_manager_insert_action_group (priv->ui_mgr, priv->actions_image, 0);
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	priv->actions_collection = gtk_action_group_new ("MenuActionsCollection");
+	gtk_action_group_set_translation_domain (priv->actions_collection,
+						 GETTEXT_PACKAGE);
+
+	gtk_action_group_add_actions (priv->actions_collection,
+				      action_entries_collection,
+				      G_N_ELEMENTS (action_entries_collection),
+				      window);
+
+	gtk_action_group_add_toggle_actions (priv->actions_collection,
+					     toggle_entries_collection,
+					     G_N_ELEMENTS (toggle_entries_collection),
+					     window);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	set_action_properties (priv->actions_window,
+			       priv->actions_image,
+			       priv->actions_collection);
+
+	gtk_ui_manager_insert_action_group (priv->ui_mgr, priv->actions_collection, 0);
+
+	if (!gtk_ui_manager_add_ui_from_resource (priv->ui_mgr,
+	                                          "/org/mate/eom/ui/eom-ui.xml",
+	                                          &error)) {
+		g_warning ("building menus failed: %s", error->message);
+		g_error_free (error);
+	}
+
+	g_signal_connect (priv->ui_mgr, "connect_proxy",
+			  G_CALLBACK (connect_proxy_cb), window);
+	g_signal_connect (priv->ui_mgr, "disconnect_proxy",
+			  G_CALLBACK (disconnect_proxy_cb), window);
+
+	menubar = gtk_ui_manager_get_widget (priv->ui_mgr, "/MainMenu");
+	g_assert (GTK_IS_WIDGET (menubar));
+	gtk_box_pack_start (GTK_BOX (priv->box), menubar, FALSE, FALSE, 0);
+	gtk_widget_show (menubar);
+
+	menuitem = gtk_ui_manager_get_widget (priv->ui_mgr,
+			"/MainMenu/Edit/EditFlipHorizontal");
+	gtk_image_menu_item_set_always_show_image (
+			GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
+
+	menuitem = gtk_ui_manager_get_widget (priv->ui_mgr,
+			"/MainMenu/Edit/EditFlipVertical");
+	gtk_image_menu_item_set_always_show_image (
+			GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
+
+	menuitem = gtk_ui_manager_get_widget (priv->ui_mgr,
+			"/MainMenu/Edit/EditRotate90");
+	gtk_image_menu_item_set_always_show_image (
+			GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
+
+	menuitem = gtk_ui_manager_get_widget (priv->ui_mgr,
+			"/MainMenu/Edit/EditRotate270");
+	gtk_image_menu_item_set_always_show_image (
+			GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
+
+	priv->toolbar = GTK_WIDGET
+		(g_object_new (EGG_TYPE_EDITABLE_TOOLBAR,
+			       "ui-manager", priv->ui_mgr,
+			       "popup-path", "/ToolbarPopup",
+			       "model", eom_application_get_toolbars_model (EOM_APP),
+			       NULL));
+
+	gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (priv->toolbar)),
+				     GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
+
+	egg_editable_toolbar_show (EGG_EDITABLE_TOOLBAR (priv->toolbar),
+				   "Toolbar");
+
+	gtk_box_pack_start (GTK_BOX (priv->box),
+			    priv->toolbar,
+			    FALSE,
+			    FALSE,
+			    0);
+
+	gtk_widget_show (priv->toolbar);
+
+	gtk_window_add_accel_group (GTK_WINDOW (window),
+				    gtk_ui_manager_get_accel_group (priv->ui_mgr));
+
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+	priv->actions_recent = gtk_action_group_new ("RecentFilesActions");
+	gtk_action_group_set_translation_domain (priv->actions_recent,
+						 GETTEXT_PACKAGE);
+	G_GNUC_END_IGNORE_DEPRECATIONS;
+
+	g_signal_connect (gtk_recent_manager_get_default (), "changed",
+			  G_CALLBACK (eom_window_recent_manager_changed_cb),
+			  window);
+
+	eom_window_update_recent_files_menu (window);
+
+	gtk_ui_manager_insert_action_group (priv->ui_mgr, priv->actions_recent, 0);
+
+	priv->cbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+	gtk_box_pack_start (GTK_BOX (priv->box), priv->cbox, TRUE, TRUE, 0);
+	gtk_widget_show (priv->cbox);
+
+	priv->statusbar = eom_statusbar_new ();
+	gtk_box_pack_end (GTK_BOX (priv->box),
+			  GTK_WIDGET (priv->statusbar),
+			  FALSE, FALSE, 0);
+	gtk_widget_show (priv->statusbar);
+
+	priv->image_info_message_cid =
+		gtk_statusbar_get_context_id (GTK_STATUSBAR (priv->statusbar),
+					      "image_info_message");
+	priv->tip_message_cid =
+		gtk_statusbar_get_context_id (GTK_STATUSBAR (priv->statusbar),
+					      "tip_message");
+
+	priv->layout = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+
+	hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
+
+	priv->sidebar = eom_sidebar_new ();
+	/* The sidebar shouldn't be shown automatically on show_all(),
+	   but only when the user actually wants it. */
+	gtk_widget_set_no_show_all (priv->sidebar, TRUE);
+
+	gtk_widget_set_size_request (priv->sidebar, 210, -1);
+
+	g_signal_connect_after (priv->sidebar,
+				"show",
+				G_CALLBACK (eom_window_sidebar_visibility_changed),
+				window);
+
+	g_signal_connect_after (priv->sidebar,
+				"hide",
+				G_CALLBACK (eom_window_sidebar_visibility_changed),
+				window);
+
+	g_signal_connect_after (priv->sidebar,
+				"page-added",
+				G_CALLBACK (eom_window_sidebar_page_added),
+				window);
+
+	g_signal_connect_after (priv->sidebar,
+				"page-removed",
+				G_CALLBACK (eom_window_sidebar_page_removed),
+				window);
+
+ 	priv->view = eom_scroll_view_new ();
+
+	eom_sidebar_add_page (EOM_SIDEBAR (priv->sidebar),
+			      _("Properties"),
+			      GTK_WIDGET (eom_metadata_sidebar_new (window)));
+
+	gtk_widget_set_size_request (GTK_WIDGET (priv->view), 100, 100);
+	g_signal_connect (G_OBJECT (priv->view),
+			  "zoom_changed",
+			  G_CALLBACK (view_zoom_changed_cb),
+			  window);
+
+	g_settings_bind (priv->view_settings, EOM_CONF_VIEW_SCROLL_WHEEL_ZOOM,
+			 priv->view, "scrollwheel-zoom", G_SETTINGS_BIND_GET);
+	g_settings_bind (priv->view_settings, EOM_CONF_VIEW_ZOOM_MULTIPLIER,
+			 priv->view, "zoom-multiplier", G_SETTINGS_BIND_GET);
+
+	view_popup = gtk_ui_manager_get_widget (priv->ui_mgr, "/ViewPopup");
+	eom_scroll_view_set_popup (EOM_SCROLL_VIEW (priv->view),
+				   GTK_MENU (view_popup));
+
+	gtk_paned_pack1 (GTK_PANED (hpaned),
+			 priv->sidebar,
+			 FALSE,
+			 FALSE);
+
+	gtk_paned_pack2 (GTK_PANED (hpaned),
+			 priv->view,
+			 TRUE,
+			 FALSE);
+
+	gtk_widget_show_all (hpaned);
+
+	gtk_box_pack_start (GTK_BOX (priv->layout), hpaned, TRUE, TRUE, 0);
+
+	priv->thumbview = g_object_ref (eom_thumb_view_new ());
+
+	/* giving shape to the view */
+	gtk_icon_view_set_margin (GTK_ICON_VIEW (priv->thumbview), 4);
+	gtk_icon_view_set_row_spacing (GTK_ICON_VIEW (priv->thumbview), 0);
+
+	g_signal_connect (G_OBJECT (priv->thumbview), "selection_changed",
+			  G_CALLBACK (handle_image_selection_changed_cb), window);
+
+	priv->nav = eom_thumb_nav_new (priv->thumbview,
+				       EOM_THUMB_NAV_MODE_ONE_ROW,
+				       g_settings_get_boolean (priv->ui_settings,
+							      EOM_CONF_UI_SCROLL_BUTTONS));
+
+	// Bind the scroll buttons to their GSettings key
+	g_settings_bind (priv->ui_settings, EOM_CONF_UI_SCROLL_BUTTONS,
+			 priv->nav, "show-buttons", G_SETTINGS_BIND_GET);
+
+	thumb_popup = gtk_ui_manager_get_widget (priv->ui_mgr, "/ThumbnailPopup");
+	eom_thumb_view_set_thumbnail_popup (EOM_THUMB_VIEW (priv->thumbview),
+					    GTK_MENU (thumb_popup));
+
+	gtk_box_pack_start (GTK_BOX (priv->layout), priv->nav, FALSE, FALSE, 0);
+
+	gtk_box_pack_end (GTK_BOX (priv->cbox), priv->layout, TRUE, TRUE, 0);
+
+	eom_window_can_save_changed_cb (priv->lockdown_settings,
+					EOM_CONF_LOCKDOWN_CAN_SAVE,
+					window);
+	g_settings_bind (priv->ui_settings, EOM_CONF_UI_IMAGE_COLLECTION_POSITION,
+			 window, "collection-position", G_SETTINGS_BIND_GET);
+	g_settings_bind (priv->ui_settings, EOM_CONF_UI_IMAGE_COLLECTION_RESIZABLE,
+			 window, "collection-resizable", G_SETTINGS_BIND_GET);
+
+	update_action_groups_state (window);
+
+	if ((priv->flags & EOM_STARTUP_FULLSCREEN) ||
+	    (priv->flags & EOM_STARTUP_SLIDE_SHOW)) {
+		eom_window_run_fullscreen (window, (priv->flags & EOM_STARTUP_SLIDE_SHOW));
+	} else {
+		priv->mode = EOM_WINDOW_MODE_NORMAL;
+		update_ui_visibility (window);
+	}
+
+	eom_window_set_drag_dest (window);
+}
+
+static void
+eom_window_init (EomWindow *window)
+{
+	GdkGeometry hints;
+	GdkScreen *screen;
+	EomWindowPrivate *priv;
+
+	eom_debug (DEBUG_WINDOW);
+
+	GtkStyleContext *context;
+
+	context = gtk_widget_get_style_context (GTK_WIDGET (window));
+	gtk_style_context_add_class (context, "eom-window");
+
+	hints.min_width  = EOM_WINDOW_MIN_WIDTH;
+	hints.min_height = EOM_WINDOW_MIN_HEIGHT;
+
+	screen = gtk_widget_get_screen (GTK_WIDGET (window));<--- Variable 'screen' is assigned a value that is never used.
+
+	priv = window->priv = eom_window_get_instance_private (window);
+
+	priv->view_settings = g_settings_new (EOM_CONF_VIEW);
+	priv->ui_settings = g_settings_new (EOM_CONF_UI);
+	priv->fullscreen_settings = g_settings_new (EOM_CONF_FULLSCREEN);
+	priv->lockdown_settings = g_settings_new (EOM_CONF_LOCKDOWN_SCHEMA);
+
+	g_signal_connect (priv->lockdown_settings,
+					  "changed::" EOM_CONF_LOCKDOWN_CAN_SAVE,
+					  G_CALLBACK (eom_window_can_save_changed_cb),
+					  window);
+
+	window->priv->store = NULL;
+	window->priv->image = NULL;
+
+	window->priv->fullscreen_popup = NULL;
+	window->priv->fullscreen_timeout_source = NULL;
+	window->priv->slideshow_random = FALSE;
+	window->priv->slideshow_loop = FALSE;
+	window->priv->slideshow_switch_timeout = 0;
+	window->priv->slideshow_switch_source = NULL;
+	window->priv->fullscreen_idle_inhibit_cookie = 0;
+
+	gtk_window_set_geometry_hints (GTK_WINDOW (window),
+				       GTK_WIDGET (window),
+				       &hints,
+				       GDK_HINT_MIN_SIZE);
+
+	gtk_window_set_default_size (GTK_WINDOW (window),
+				     EOM_WINDOW_DEFAULT_WIDTH,
+				     EOM_WINDOW_DEFAULT_HEIGHT);
+
+	gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
+
+	window->priv->mode = EOM_WINDOW_MODE_UNKNOWN;
+	window->priv->status = EOM_WINDOW_STATUS_UNKNOWN;
+
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+	window->priv->display_profile =
+		eom_window_get_display_profile (screen);
+#endif
+
+	window->priv->recent_menu_id = 0;
+
+	window->priv->collection_position = 0;
+	window->priv->collection_resizable = FALSE;
+
+	window->priv->save_disabled = FALSE;
+
+	window->priv->page_setup = NULL;
+
+	gtk_window_set_application (GTK_WINDOW (window), GTK_APPLICATION (EOM_APP));
+}
+
+static void
+eom_window_dispose (GObject *object)
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (EOM_IS_WINDOW (object));
+
+	eom_debug (DEBUG_WINDOW);
+
+	window = EOM_WINDOW (object);
+	priv = window->priv;
+
+	peas_engine_garbage_collect (PEAS_ENGINE (EOM_APP->priv->plugin_engine));
+
+	if (priv->extensions != NULL) {
+		g_object_unref (priv->extensions);
+		priv->extensions = NULL;
+		peas_engine_garbage_collect (PEAS_ENGINE (EOM_APP->priv->plugin_engine));
+	}
+
+	if (priv->page_setup != NULL) {
+		g_object_unref (priv->page_setup);
+		priv->page_setup = NULL;
+	}
+
+	if (priv->thumbview)
+	{
+		/* Disconnect so we don't get any unwanted callbacks
+		 * when the thumb view is disposed. */
+		g_signal_handlers_disconnect_by_func (priv->thumbview,
+		                 G_CALLBACK (handle_image_selection_changed_cb),
+		                 window);
+		g_clear_object (&priv->thumbview);
+	}
+
+	if (priv->store != NULL) {
+		g_signal_handlers_disconnect_by_func (priv->store,
+					      eom_window_list_store_image_added,
+					      window);
+		g_signal_handlers_disconnect_by_func (priv->store,
+					    eom_window_list_store_image_removed,
+					    window);
+		g_object_unref (priv->store);
+		priv->store = NULL;
+	}
+
+	if (priv->image != NULL) {
+	  	g_signal_handlers_disconnect_by_func (priv->image,
+						      image_thumb_changed_cb,
+						      window);
+		g_signal_handlers_disconnect_by_func (priv->image,
+						      image_file_changed_cb,
+						      window);
+		g_object_unref (priv->image);
+		priv->image = NULL;
+	}
+
+	if (priv->actions_window != NULL) {
+		g_object_unref (priv->actions_window);
+		priv->actions_window = NULL;
+	}
+
+	if (priv->actions_image != NULL) {
+		g_object_unref (priv->actions_image);
+		priv->actions_image = NULL;
+	}
+
+	if (priv->actions_collection != NULL) {
+		g_object_unref (priv->actions_collection);
+		priv->actions_collection = NULL;
+	}
+
+	if (priv->actions_recent != NULL) {
+		g_object_unref (priv->actions_recent);
+		priv->actions_recent = NULL;
+	}
+
+        if (priv->actions_open_with != NULL) {
+                g_object_unref (priv->actions_open_with);
+                priv->actions_open_with = NULL;
+        }
+
+	fullscreen_clear_timeout (window);
+
+	if (window->priv->fullscreen_popup != NULL) {
+		gtk_widget_destroy (priv->fullscreen_popup);
+		priv->fullscreen_popup = NULL;
+	}
+
+	slideshow_clear_timeout (window);
+	eom_window_uninhibit_screensaver (window);
+
+	g_signal_handlers_disconnect_by_func (gtk_recent_manager_get_default (),
+					      G_CALLBACK (eom_window_recent_manager_changed_cb),
+					      window);
+
+	priv->recent_menu_id = 0;
+
+	eom_window_clear_load_job (window);
+
+	eom_window_clear_transform_job (window);
+
+	if (priv->view_settings) {
+		g_object_unref (priv->view_settings);
+		priv->view_settings = NULL;
+	}
+	if (priv->ui_settings) {
+		g_object_unref (priv->ui_settings);
+		priv->ui_settings = NULL;
+	}
+	if (priv->fullscreen_settings) {
+		g_object_unref (priv->fullscreen_settings);
+		priv->fullscreen_settings = NULL;
+	}
+	if (priv->lockdown_settings) {
+		g_object_unref (priv->lockdown_settings);
+		priv->lockdown_settings = NULL;
+	}
+
+	if (priv->file_list != NULL) {
+		g_slist_free_full (priv->file_list, g_object_unref);
+		priv->file_list = NULL;
+	}
+
+#if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
+	if (priv->display_profile != NULL) {
+		cmsCloseProfile (priv->display_profile);
+		priv->display_profile = NULL;
+	}
+#endif
+
+	if (priv->last_save_as_folder != NULL) {
+		g_object_unref (priv->last_save_as_folder);
+		priv->last_save_as_folder = NULL;
+	}
+
+	peas_engine_garbage_collect (PEAS_ENGINE (EOM_APP->priv->plugin_engine));
+
+	G_OBJECT_CLASS (eom_window_parent_class)->dispose (object);
+}
+
+static gint
+eom_window_delete (GtkWidget *widget, GdkEventAny *event)
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+
+	g_return_val_if_fail (EOM_IS_WINDOW (widget), FALSE);
+
+	window = EOM_WINDOW (widget);
+	priv = window->priv;
+
+	if (priv->save_job != NULL) {
+		eom_window_finish_saving (window);
+	}
+
+	if (eom_window_unsaved_images_confirm (window)) {
+		return TRUE;
+	}
+
+	gtk_widget_destroy (widget);
+
+	return TRUE;
+}
+
+static gint
+eom_window_key_press (GtkWidget *widget, GdkEventKey *event)
+{
+	GtkContainer *tbcontainer = GTK_CONTAINER ((EOM_WINDOW (widget)->priv->toolbar));
+	gint result = FALSE;
+	gboolean handle_selection = FALSE;
+
+	switch (event->keyval) {
+	case GDK_KEY_space:
+		if (event->state & GDK_CONTROL_MASK) {
+			handle_selection = TRUE;
+			break;
+		}
+	case GDK_KEY_Return:
+		if (gtk_container_get_focus_child (tbcontainer) == NULL) {
+			/* Image properties dialog case */
+			if (event->state & GDK_MOD1_MASK) {
+				result = FALSE;
+				break;
+			}
+
+			if (event->state & GDK_SHIFT_MASK) {
+				eom_window_cmd_go_prev (NULL, EOM_WINDOW (widget));
+			} else {
+				eom_window_cmd_go_next (NULL, EOM_WINDOW (widget));
+			}
+			result = TRUE;
+		}
+		break;
+	case GDK_KEY_p:
+	case GDK_KEY_P:
+		if (EOM_WINDOW (widget)->priv->mode == EOM_WINDOW_MODE_FULLSCREEN || EOM_WINDOW (widget)->priv->mode == EOM_WINDOW_MODE_SLIDESHOW) {
+			gboolean slideshow;
+
+			slideshow = EOM_WINDOW (widget)->priv->mode == EOM_WINDOW_MODE_SLIDESHOW;
+			eom_window_run_fullscreen (EOM_WINDOW (widget), !slideshow);
+		}
+		break;
+	case GDK_KEY_Q:
+	case GDK_KEY_q:
+	case GDK_KEY_Escape:
+		if (EOM_WINDOW (widget)->priv->mode == EOM_WINDOW_MODE_FULLSCREEN) {
+			eom_window_stop_fullscreen (EOM_WINDOW (widget), FALSE);
+		} else if (EOM_WINDOW (widget)->priv->mode == EOM_WINDOW_MODE_SLIDESHOW) {
+			eom_window_stop_fullscreen (EOM_WINDOW (widget), TRUE);
+		} else {
+			eom_window_cmd_close_window (NULL, EOM_WINDOW (widget));
+			return TRUE;
+		}
+		break;
+	case GDK_KEY_Left:
+		if (event->state & GDK_MOD1_MASK) {
+			/* Alt+Left moves to previous image */
+			if (is_rtl) { /* move to next in RTL mode */
+				eom_window_cmd_go_next (NULL, EOM_WINDOW (widget));
+			} else {
+				eom_window_cmd_go_prev (NULL, EOM_WINDOW (widget));
+			}
+			result = TRUE;
+			break;
+		} /* else fall-trough is intended */
+	case GDK_KEY_Up:
+		if (eom_scroll_view_scrollbars_visible (EOM_SCROLL_VIEW (EOM_WINDOW (widget)->priv->view))) {
+			/* break to let scrollview handle the key */
+			break;
+		}
+		if (gtk_container_get_focus_child (tbcontainer) != NULL)
+			break;
+		if (!gtk_widget_get_visible (EOM_WINDOW (widget)->priv->nav)) {
+			if (is_rtl && event->keyval == GDK_KEY_Left) {
+				/* handle RTL fall-through,
+				 * need to behave like GDK_Down then */
+				eom_window_cmd_go_next (NULL,
+							EOM_WINDOW (widget));
+			} else {
+				eom_window_cmd_go_prev (NULL,
+							EOM_WINDOW (widget));
+			}
+			result = TRUE;
+			break;
+		}
+	case GDK_KEY_Right:
+		if (event->state & GDK_MOD1_MASK) {
+			/* Alt+Right moves to next image */
+			if (is_rtl) { /* move to previous in RTL mode */
+				eom_window_cmd_go_prev (NULL, EOM_WINDOW (widget));
+			} else {
+				eom_window_cmd_go_next (NULL, EOM_WINDOW (widget));
+			}
+			result = TRUE;
+			break;
+		} /* else fall-trough is intended */
+	case GDK_KEY_Down:
+		if (eom_scroll_view_scrollbars_visible (EOM_SCROLL_VIEW (EOM_WINDOW (widget)->priv->view))) {
+			/* break to let scrollview handle the key */
+			break;
+		}
+		if (gtk_container_get_focus_child (tbcontainer) != NULL)
+			break;
+		if (!gtk_widget_get_visible (EOM_WINDOW (widget)->priv->nav)) {
+			if (is_rtl && event->keyval == GDK_KEY_Right) {
+				/* handle RTL fall-through,
+				 * need to behave like GDK_Up then */
+				eom_window_cmd_go_prev (NULL,
+							EOM_WINDOW (widget));
+			} else {
+				eom_window_cmd_go_next (NULL,
+							EOM_WINDOW (widget));
+			}
+			result = TRUE;
+			break;
+		}
+	case GDK_KEY_Page_Up:
+		if (!eom_scroll_view_scrollbars_visible (EOM_SCROLL_VIEW (EOM_WINDOW (widget)->priv->view))) {
+			if (!gtk_widget_get_visible (EOM_WINDOW (widget)->priv->nav)) {
+				/* If the iconview is not visible skip to the
+				 * previous image manually as it won't handle
+				 * the keypress then. */
+				eom_window_cmd_go_prev (NULL,
+							EOM_WINDOW (widget));
+				result = TRUE;
+			} else
+				handle_selection = TRUE;
+		}
+		break;
+	case GDK_KEY_Page_Down:
+		if (!eom_scroll_view_scrollbars_visible (EOM_SCROLL_VIEW (EOM_WINDOW (widget)->priv->view))) {
+			if (!gtk_widget_get_visible (EOM_WINDOW (widget)->priv->nav)) {
+				/* If the iconview is not visible skip to the
+				 * next image manually as it won't handle
+				 * the keypress then. */
+				eom_window_cmd_go_next (NULL,
+							EOM_WINDOW (widget));
+				result = TRUE;
+			} else
+				handle_selection = TRUE;
+		}
+		break;
+	}
+
+	/* Update slideshow timeout */
+	if (result && (EOM_WINDOW (widget)->priv->mode == EOM_WINDOW_MODE_SLIDESHOW)) {
+		slideshow_set_timeout (EOM_WINDOW (widget));
+	}
+
+	if (handle_selection == TRUE && result == FALSE) {
+		gtk_widget_grab_focus (GTK_WIDGET (EOM_WINDOW (widget)->priv->thumbview));
+
+		result = gtk_widget_event (GTK_WIDGET (EOM_WINDOW (widget)->priv->thumbview),
+					   (GdkEvent *) event);
+	}
+
+	/* If the focus is not in the toolbar and we still haven't handled the
+	   event, give the scrollview a chance to do it.  */
+	if (!gtk_container_get_focus_child (tbcontainer) && result == FALSE &&
+		gtk_widget_get_realized (GTK_WIDGET (EOM_WINDOW (widget)->priv->view))) {
+			result = gtk_widget_event (GTK_WIDGET (EOM_WINDOW (widget)->priv->view),
+						   (GdkEvent *) event);
+	}
+
+	if (result == FALSE && GTK_WIDGET_CLASS (eom_window_parent_class)->key_press_event) {
+		result = (* GTK_WIDGET_CLASS (eom_window_parent_class)->key_press_event) (widget, event);
+	}
+
+	return result;
+}
+
+static gint
+eom_window_button_press (GtkWidget *widget, GdkEventButton *event)
+{
+	EomWindow *window = EOM_WINDOW (widget);
+	gint result = FALSE;
+
+	if (event->type == GDK_BUTTON_PRESS) {
+		switch (event->button) {
+		case 6:
+			eom_thumb_view_select_single (EOM_THUMB_VIEW (window->priv->thumbview),
+						      EOM_THUMB_VIEW_SELECT_LEFT);
+			result = TRUE;
+		       	break;
+		case 7:
+			eom_thumb_view_select_single (EOM_THUMB_VIEW (window->priv->thumbview),
+						      EOM_THUMB_VIEW_SELECT_RIGHT);
+			result = TRUE;
+		       	break;
+		}
+	}
+
+	if (result == FALSE && GTK_WIDGET_CLASS (eom_window_parent_class)->button_press_event) {
+		result = (* GTK_WIDGET_CLASS (eom_window_parent_class)->button_press_event) (widget, event);
+	}
+
+	return result;
+}
+
+static gboolean
+eom_window_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
+{
+	EomWindow *window = EOM_WINDOW (widget);
+	EomWindowPrivate *priv = window->priv;
+	gboolean fullscreen;
+
+	eom_debug (DEBUG_WINDOW);
+
+	fullscreen = priv->mode == EOM_WINDOW_MODE_FULLSCREEN ||
+		     priv->mode == EOM_WINDOW_MODE_SLIDESHOW;
+
+	if (fullscreen) {
+		gtk_widget_hide (priv->fullscreen_popup);
+	}
+
+	return GTK_WIDGET_CLASS (eom_window_parent_class)->focus_out_event (widget, event);
+}
+
+static void
+eom_window_set_property (GObject      *object,
+			 guint         property_id,
+			 const GValue *value,
+			 GParamSpec   *pspec)
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (object));
+
+	window = EOM_WINDOW (object);
+	priv = window->priv;
+
+	switch (property_id) {
+	case PROP_COLLECTION_POS:
+		eom_window_set_collection_mode (window, g_value_get_enum (value),
+					     priv->collection_resizable);
+		break;
+	case PROP_COLLECTION_RESIZABLE:
+		eom_window_set_collection_mode (window, priv->collection_position,
+					     g_value_get_boolean (value));
+		break;
+	case PROP_STARTUP_FLAGS:
+		priv->flags = g_value_get_flags (value);
+		break;
+
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+eom_window_get_property (GObject    *object,
+			 guint       property_id,
+			 GValue     *value,
+			 GParamSpec *pspec)
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+
+	g_return_if_fail (EOM_IS_WINDOW (object));
+
+	window = EOM_WINDOW (object);
+	priv = window->priv;
+
+	switch (property_id) {
+	case PROP_COLLECTION_POS:
+		g_value_set_enum (value, priv->collection_position);
+		break;
+	case PROP_COLLECTION_RESIZABLE:
+		g_value_set_boolean (value, priv->collection_resizable);
+		break;
+	case PROP_STARTUP_FLAGS:
+		g_value_set_flags (value, priv->flags);
+		break;
+
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+on_extension_added (PeasExtensionSet *set,
+		    PeasPluginInfo   *info,
+		    PeasExtension    *exten,
+		    GtkWindow        *window)
+{
+	peas_extension_call (exten, "activate", window);
+}
+
+static void
+on_extension_removed (PeasExtensionSet *set,
+		      PeasPluginInfo   *info,
+		      PeasExtension    *exten,
+		      GtkWindow        *window)
+{
+	peas_extension_call (exten, "deactivate", window);
+}
+
+static GObject *
+eom_window_constructor (GType type,
+			guint n_construct_properties,
+			GObjectConstructParam *construct_params)
+{
+	GObject *object;
+	EomWindowPrivate *priv;
+
+	object = G_OBJECT_CLASS (eom_window_parent_class)->constructor
+			(type, n_construct_properties, construct_params);
+
+	priv = EOM_WINDOW (object)->priv;
+
+	eom_window_construct_ui (EOM_WINDOW (object));
+
+	priv->extensions = peas_extension_set_new (PEAS_ENGINE (EOM_APP->priv->plugin_engine),
+	                                           EOM_TYPE_WINDOW_ACTIVATABLE,
+	                                           "window",
+	                                           EOM_WINDOW (object), NULL);
+
+	peas_extension_set_call (priv->extensions, "activate");
+
+	g_signal_connect (priv->extensions, "extension-added",
+			  G_CALLBACK (on_extension_added), object);
+	g_signal_connect (priv->extensions, "extension-removed",
+			  G_CALLBACK (on_extension_removed), object);
+
+	return object;
+}
+
+static void
+eom_window_class_init (EomWindowClass *class)
+{
+	GObjectClass *g_object_class = (GObjectClass *) class;
+	GtkWidgetClass *widget_class = (GtkWidgetClass *) class;
+
+	g_object_class->constructor = eom_window_constructor;
+	g_object_class->dispose = eom_window_dispose;
+	g_object_class->set_property = eom_window_set_property;
+	g_object_class->get_property = eom_window_get_property;
+
+	widget_class->delete_event = eom_window_delete;
+	widget_class->key_press_event = eom_window_key_press;
+	widget_class->button_press_event = eom_window_button_press;
+	widget_class->drag_data_received = eom_window_drag_data_received;
+	widget_class->focus_out_event = eom_window_focus_out_event;
+
+/**
+ * EomWindow:collection-position:
+ *
+ * Determines the position of the image collection in the window
+ * relative to the image.
+ */
+	g_object_class_install_property (
+		g_object_class, PROP_COLLECTION_POS,
+		g_param_spec_enum ("collection-position", NULL, NULL,
+				   EOM_TYPE_WINDOW_COLLECTION_POS,
+				   EOM_WINDOW_COLLECTION_POS_BOTTOM,
+				   G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
+
+/**
+ * EomWindow:collection-resizable:
+ *
+ * If %TRUE the collection will be resizable by the user otherwise it will be
+ * in single column/row mode.
+ */
+	g_object_class_install_property (
+		g_object_class, PROP_COLLECTION_RESIZABLE,
+		g_param_spec_boolean ("collection-resizable", NULL, NULL, FALSE,
+				      G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
+
+/**
+ * EomWindow:startup-flags:
+ *
+ * A bitwise OR of #EomStartupFlags elements, indicating how the window
+ * should behave upon creation.
+ */
+	g_object_class_install_property (g_object_class,
+					 PROP_STARTUP_FLAGS,
+					 g_param_spec_flags ("startup-flags",
+							     NULL,
+							     NULL,
+							     EOM_TYPE_STARTUP_FLAGS,
+					 		     0,
+					 		     G_PARAM_READWRITE |
+							     G_PARAM_CONSTRUCT_ONLY));
+
+/**
+ * EomWindow::prepared:
+ * @window: the object which received the signal.
+ *
+ * The #EomWindow::prepared signal is emitted when the @window is ready
+ * to be shown.
+ */
+	signals [SIGNAL_PREPARED] =
+		g_signal_new ("prepared",
+			      EOM_TYPE_WINDOW,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EomWindowClass, prepared),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+}
+
+/**
+ * eom_window_new:
+ * @flags: the initialization parameters for the new window.
+ *
+ *
+ * Creates a new and empty #EomWindow. Use @flags to indicate
+ * if the window should be initialized fullscreen, in slideshow mode,
+ * and/or without the thumbnails collection visible. See #EomStartupFlags.
+ *
+ * Returns: a newly created #EomWindow.
+ **/
+GtkWidget*
+eom_window_new (EomStartupFlags flags)
+{
+	EomWindow *window;
+
+	eom_debug (DEBUG_WINDOW);
+
+	window = EOM_WINDOW (g_object_new (EOM_TYPE_WINDOW,
+	                                   "type", GTK_WINDOW_TOPLEVEL,
+	                                   "application", EOM_APP,
+	                                   "show-menubar", FALSE,
+	                                   "startup-flags", flags,
+	                                   NULL));
+
+	return GTK_WIDGET (window);
+}
+
+static void
+eom_window_list_store_image_added (GtkTreeModel *tree_model,
+                                   GtkTreePath  *path,
+                                   GtkTreeIter  *iter,
+                                   gpointer      user_data)
+{
+	EomWindow *window = EOM_WINDOW (user_data);
+
+	update_image_pos (window);
+	update_action_groups_state (window);
+}
+
+static void
+eom_window_list_store_image_removed (GtkTreeModel *tree_model,
+                                     GtkTreePath  *path,
+                                     gpointer      user_data)
+{
+	EomWindow *window = EOM_WINDOW (user_data);
+
+	update_image_pos (window);
+	update_action_groups_state (window);
+}
+
+static void
+eom_job_model_cb (EomJobModel *job, gpointer data)
+{
+	EomWindow *window;
+	EomWindowPrivate *priv;
+	gint n_images;
+
+	eom_debug (DEBUG_WINDOW);
+
+#ifdef HAVE_EXIF
+	int i;
+	EomImage *image;
+#endif
+
+	g_return_if_fail (EOM_IS_WINDOW (data));
+
+	window = EOM_WINDOW (data);
+	priv = window->priv;
+
+	if (priv->store != NULL) {
+		g_object_unref (priv->store);
+		priv->store = NULL;
+	}
+
+	priv->store = g_object_ref (job->store);
+
+	n_images = eom_list_store_length (EOM_LIST_STORE (priv->store));
+
+#ifdef HAVE_EXIF
+	if (g_settings_get_boolean (priv->view_settings, EOM_CONF_VIEW_AUTOROTATE)) {
+		for (i = 0; i < n_images; i++) {
+			image = eom_list_store_get_image_by_pos (priv->store, i);
+			eom_image_autorotate (image);
+			g_object_unref (image);
+		}
+	}
+#endif
+
+	eom_thumb_view_set_model (EOM_THUMB_VIEW (priv->thumbview), priv->store);
+
+	g_signal_connect (G_OBJECT (priv->store),
+			  "row-inserted",
+			  G_CALLBACK (eom_window_list_store_image_added),
+			  window);
+
+	g_signal_connect (G_OBJECT (priv->store),
+			  "row-deleted",
+			  G_CALLBACK (eom_window_list_store_image_removed),
+			  window);
+
+	if (n_images == 0) {
+		gint n_files;
+
+		priv->status = EOM_WINDOW_STATUS_NORMAL;
+		update_action_groups_state (window);
+
+		n_files = g_slist_length (priv->file_list);
+
+		if (n_files > 0) {
+			GtkWidget *message_area;
+			GFile *file = NULL;
+
+			if (n_files == 1) {
+				file = (GFile *) priv->file_list->data;
+			}
+
+			message_area = eom_no_images_error_message_area_new (file);
+
+			eom_window_set_message_area (window, message_area);
+
+			gtk_widget_show (message_area);
+		}
+
+		g_signal_emit (window, signals[SIGNAL_PREPARED], 0);
+	}
+}
+
+/**
+ * eom_window_open_file_list:
+ * @window: An #EomWindow.
+ * @file_list: (element-type GFile): A %NULL-terminated list of #GFile's.
+ *
+ * Opens a list of files, adding them to the collection in @window.
+ * Files will be checked to be readable and later filtered according
+ * with eom_list_store_add_files().
+ **/
+void
+eom_window_open_file_list (EomWindow *window, GSList *file_list)
+{
+	EomJob *job;
+
+	eom_debug (DEBUG_WINDOW);
+
+	window->priv->status = EOM_WINDOW_STATUS_INIT;
+
+	g_slist_foreach (file_list, (GFunc) g_object_ref, NULL);
+	window->priv->file_list = file_list;
+
+	job = eom_job_model_new (file_list);
+
+	g_signal_connect (job,
+			  "finished",
+			  G_CALLBACK (eom_job_model_cb),
+			  window);
+
+	eom_job_queue_add_job (job);
+	g_object_unref (job);
+}
+
+/**
+ * eom_window_get_ui_manager:
+ * @window: An #EomWindow.
+ *
+ * Gets the #GtkUIManager that describes the UI of @window.
+ *
+ * Returns: (transfer none): A #GtkUIManager.
+ **/
+GtkUIManager *
+eom_window_get_ui_manager (EomWindow *window)
+{
+	g_return_val_if_fail (EOM_IS_WINDOW (window), NULL);
+
+	return window->priv->ui_mgr;
+}
+
+/**
+ * eom_window_get_mode:
+ * @window: An #EomWindow.
+ *
+ * Gets the mode of @window. See #EomWindowMode for details.
+ *
+ * Returns: An #EomWindowMode.
+ **/
+EomWindowMode
+eom_window_get_mode (EomWindow *window)
+{
+	g_return_val_if_fail (EOM_IS_WINDOW (window), EOM_WINDOW_MODE_UNKNOWN);
+
+	return window->priv->mode;
+}
+
+/**
+ * eom_window_set_mode:
+ * @window: an #EomWindow.
+ * @mode: an #EomWindowMode value.
+ *
+ * Changes the mode of @window to normal, fullscreen, or slideshow.
+ * See #EomWindowMode for details.
+ **/
+void
+eom_window_set_mode (EomWindow *window, EomWindowMode mode)
+{
+	g_return_if_fail (EOM_IS_WINDOW (window));
+
+	if (window->priv->mode == mode)
+		return;
+
+	switch (mode) {
+	case EOM_WINDOW_MODE_NORMAL:
+		eom_window_stop_fullscreen (window,
+					    window->priv->mode == EOM_WINDOW_MODE_SLIDESHOW);
+		break;
+	case EOM_WINDOW_MODE_FULLSCREEN:
+		eom_window_run_fullscreen (window, FALSE);
+		break;
+	case EOM_WINDOW_MODE_SLIDESHOW:
+		eom_window_run_fullscreen (window, TRUE);
+		break;
+	case EOM_WINDOW_MODE_UNKNOWN:
+		break;
+	}
+}
+
+/**
+ * eom_window_get_store:
+ * @window: An #EomWindow.
+ *
+ * Gets the #EomListStore that contains the images in the collection
+ * of @window.
+ *
+ * Returns: (transfer none): an #EomListStore.
+ **/
+EomListStore *
+eom_window_get_store (EomWindow *window)
+{
+	g_return_val_if_fail (EOM_IS_WINDOW (window), NULL);
+
+	return EOM_LIST_STORE (window->priv->store);
+}
+
+/**
+ * eom_window_get_view:
+ * @window: An #EomWindow.
+ *
+ * Gets the #EomScrollView in the window.
+ *
+ * Returns: (transfer none): the #EomScrollView.
+ **/
+GtkWidget *
+eom_window_get_view (EomWindow *window)
+{
+	g_return_val_if_fail (EOM_IS_WINDOW (window), NULL);
+
+	return window->priv->view;
+}
+
+/**
+ * eom_window_get_sidebar:
+ * @window: An #EomWindow.
+ *
+ * Gets the sidebar widget of @window.
+ *
+ * Returns: (transfer none): the #EomSidebar.
+ **/
+GtkWidget *
+eom_window_get_sidebar (EomWindow *window)
+{
+	g_return_val_if_fail (EOM_IS_WINDOW (window), NULL);
+
+	return window->priv->sidebar;
+}
+
+/**
+ * eom_window_get_thumb_view:
+ * @window: an #EomWindow.
+ *
+ * Gets the thumbnails view in @window.
+ *
+ * Returns: (transfer none): an #EomThumbView.
+ **/
+GtkWidget *
+eom_window_get_thumb_view (EomWindow *window)
+{
+	g_return_val_if_fail (EOM_IS_WINDOW (window), NULL);
+
+	return window->priv->thumbview;
+}
+
+/**
+ * eom_window_get_thumb_nav:
+ * @window: an #EomWindow.
+ *
+ * Gets the thumbnails navigation pane in @window.
+ *
+ * Returns: (transfer none): an #EomThumbNav.
+ **/
+GtkWidget *
+eom_window_get_thumb_nav (EomWindow *window)
+{
+	g_return_val_if_fail (EOM_IS_WINDOW (window), NULL);
+
+	return window->priv->nav;
+}
+
+/**
+ * eom_window_get_statusbar:
+ * @window: an #EomWindow.
+ *
+ * Gets the statusbar in @window.
+ *
+ * Returns: (transfer none): a #EomStatusBar.
+ **/
+GtkWidget *
+eom_window_get_statusbar (EomWindow *window)
+{
+	g_return_val_if_fail (EOM_IS_WINDOW (window), NULL);
+
+	return window->priv->statusbar;
+}
+
+/**
+ * eom_window_get_image:
+ * @window: an #EomWindow.
+ *
+ * Gets the image currently displayed in @window or %NULL if
+ * no image is being displayed.
+ *
+ * Returns: (transfer none): an #EomImage.
+ **/
+EomImage *
+eom_window_get_image (EomWindow *window)
+{
+	g_return_val_if_fail (EOM_IS_WINDOW (window), NULL);
+
+	return window->priv->image;
+}
+
+/**
+ * eom_window_is_empty:
+ * @window: an #EomWindow.
+ *
+ * Tells whether @window is currently empty or not.
+ *
+ * Returns: %TRUE if @window has no images, %FALSE otherwise.
+ **/
+gboolean
+eom_window_is_empty (EomWindow *window)
+{
+	EomWindowPrivate *priv;
+	gboolean empty = TRUE;
+
+	eom_debug (DEBUG_WINDOW);
+
+	g_return_val_if_fail (EOM_IS_WINDOW (window), FALSE);
+
+	priv = window->priv;
+
+	if (priv->store != NULL) {
+		empty = (eom_list_store_length (EOM_LIST_STORE (priv->store)) == 0);
+	}
+
+	return empty;
+}
+
+void
+eom_window_reload_image (EomWindow *window)
+{
+	GtkWidget *view;
+
+	g_return_if_fail (EOM_IS_WINDOW (window));
+
+	if (window->priv->image == NULL)
+		return;
+
+	g_object_unref (window->priv->image);
+	window->priv->image = NULL;
+
+	view = eom_window_get_view (window);
+	eom_scroll_view_set_image (EOM_SCROLL_VIEW (view), NULL);
+
+	eom_thumb_view_select_single (EOM_THUMB_VIEW (window->priv->thumbview),
+				      EOM_THUMB_VIEW_SELECT_CURRENT);
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/3.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/3.html new file mode 100644 index 0000000..7541856 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/3.html @@ -0,0 +1,2246 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2001, 2002 The Free Software Foundation, Inc.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* based upon file transupp.c from the libjpeg package, original copyright
+ * note follows:
+.*
+ *
+ * transupp.c
+ *
+ * Copyright (C) 1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains image transformation routines and other utility code
+ * used by the jpegtran sample application.  These are NOT part of the core
+ * JPEG library.  But we keep these routines separate from jpegtran.c to
+ * ease the task of maintaining jpegtran-like programs that have other user
+ * interfaces.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_LIBJPEG
+
+#define SAVE_MARKERS_SUPPORTED 1
+
+#include <stdio.h>
+#include <jpeglib.h>
+#include "transupp-6b.h"		/* My own external interface */
+
+#ifndef MAX
+#define MAX(a, b)  (((a) > (b)) ? (a) : (b))
+#endif
+
+enum {
+  JERR_CONVERSION_NOTIMPL
+};
+
+#define ERREXIT(cinfo,code)  \
+  ((cinfo)->err->msg_code = (code), \
+   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+
+
+static long
+jround_up (long a, long b)
+/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */
+/* Assumes a >= 0, b > 0 */
+{
+  a += b - 1L;
+  return a - (a % b);
+}
+
+
+static void
+jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row,
+		 JDIMENSION num_blocks)
+/* Copy a row of coefficient blocks from one place to another. */
+{
+  register JCOEFPTR inptr, outptr;
+  register long count;
+
+  inptr = (JCOEFPTR) input_row;
+  outptr = (JCOEFPTR) output_row;
+  for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) {
+    *outptr++ = *inptr++;
+  }
+}
+
+
+/*
+ * Lossless image transformation routines.  These routines work on DCT
+ * coefficient arrays and thus do not require any lossy decompression
+ * or recompression of the image.
+ * Thanks to Guido Vollbeding for the initial design and code of this feature.
+ *
+ * Horizontal flipping is done in-place, using a single top-to-bottom
+ * pass through the virtual source array.  It will thus be much the
+ * fastest option for images larger than main memory.
+ *
+ * The other routines require a set of destination virtual arrays, so they
+ * need twice as much memory as jpegtran normally does.  The destination
+ * arrays are always written in normal scan order (top to bottom) because
+ * the virtual array manager expects this.  The source arrays will be scanned
+ * in the corresponding order, which means multiple passes through the source
+ * arrays for most of the transforms.  That could result in much thrashing
+ * if the image is larger than main memory.
+ *
+ * Some notes about the operating environment of the individual transform
+ * routines:
+ * 1. Both the source and destination virtual arrays are allocated from the
+ *    source JPEG object, and therefore should be manipulated by calling the
+ *    source's memory manager.
+ * 2. The destination's component count should be used.  It may be smaller
+ *    than the source's when forcing to grayscale.
+ * 3. Likewise the destination's sampling factors should be used.  When
+ *    forcing to grayscale the destination's sampling factors will be all 1,
+ *    and we may as well take that as the effective iMCU size.
+ * 4. When "trim" is in effect, the destination's dimensions will be the
+ *    trimmed values but the source's will be untrimmed.
+ * 5. All the routines assume that the source and destination buffers are
+ *    padded out to a full iMCU boundary.  This is true, although for the
+ *    source buffer it is an undocumented property of jdcoefct.c.
+ * Notes 2,3,4 boil down to this: generally we should use the destination's
+ * dimensions and ignore the source's.
+ */
+
+
+static void
+do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	   jvirt_barray_ptr *src_coef_arrays)
+/* Horizontal flip; done in-place, so no separate dest array is required */
+{
+  JDIMENSION MCU_cols, comp_width, blk_x, blk_y;
+  int ci, k, offset_y;
+  JBLOCKARRAY buffer;
+  JCOEFPTR ptr1, ptr2;
+  JCOEF temp1, temp2;
+  jpeg_component_info *compptr;
+
+  /* Horizontal mirroring of DCT blocks is accomplished by swapping
+   * pairs of blocks in-place.  Within a DCT block, we perform horizontal
+   * mirroring by changing the signs of odd-numbered columns.
+   * Partial iMCUs at the right edge are left untouched.
+   */
+  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_width = MCU_cols * compptr->h_samp_factor;
+    for (blk_y = 0; blk_y < compptr->height_in_blocks;
+	 blk_y += compptr->v_samp_factor) {
+      buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+	for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
+	  ptr1 = buffer[offset_y][blk_x];
+	  ptr2 = buffer[offset_y][comp_width - blk_x - 1];
+	  /* this unrolled loop doesn't need to know which row it's on... */
+	  for (k = 0; k < DCTSIZE2; k += 2) {
+	    temp1 = *ptr1;	/* swap even column */
+	    temp2 = *ptr2;
+	    *ptr1++ = temp2;
+	    *ptr2++ = temp1;
+	    temp1 = *ptr1;	/* swap odd column with sign change */
+	    temp2 = *ptr2;
+	    *ptr1++ = -temp2;
+	    *ptr2++ = -temp1;
+	  }
+	}
+      }
+    }
+  }
+}
+
+
+static void
+do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	   jvirt_barray_ptr *src_coef_arrays,
+	   jvirt_barray_ptr *dst_coef_arrays)
+/* Vertical flip */
+{
+  JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
+  int ci, i, j, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JBLOCKROW src_row_ptr, dst_row_ptr;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  /* We output into a separate array because we can't touch different
+   * rows of the source virtual array simultaneously.  Otherwise, this
+   * is a pretty straightforward analog of horizontal flip.
+   * Within a DCT block, vertical mirroring is done by changing the signs
+   * of odd-numbered rows.
+   * Partial iMCUs at the bottom edge are copied verbatim.
+   */
+  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_height = MCU_rows * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+	 dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
+      if (dst_blk_y < comp_height) {
+	/* Row is within the mirrorable area. */
+	src_buffer = (*srcinfo->mem->access_virt_barray)
+	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	   comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
+	   (JDIMENSION) compptr->v_samp_factor, FALSE);
+      } else {
+	/* Bottom-edge blocks will be copied verbatim. */
+	src_buffer = (*srcinfo->mem->access_virt_barray)
+	  ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
+	   (JDIMENSION) compptr->v_samp_factor, FALSE);
+      }
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+	if (dst_blk_y < comp_height) {
+	  /* Row is within the mirrorable area. */
+	  dst_row_ptr = dst_buffer[offset_y];
+	  src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
+	  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+	       dst_blk_x++) {
+	    dst_ptr = dst_row_ptr[dst_blk_x];
+	    src_ptr = src_row_ptr[dst_blk_x];
+	    for (i = 0; i < DCTSIZE; i += 2) {
+	      /* copy even row */
+	      for (j = 0; j < DCTSIZE; j++)
+		*dst_ptr++ = *src_ptr++;
+	      /* copy odd row with sign change */
+	      for (j = 0; j < DCTSIZE; j++)
+		*dst_ptr++ = - *src_ptr++;
+	    }
+	  }
+	} else {
+	  /* Just copy row verbatim. */
+	  jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y],
+			  compptr->width_in_blocks);
+	}
+      }
+    }
+  }
+}
+
+
+static void
+do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	      jvirt_barray_ptr *src_coef_arrays,
+	      jvirt_barray_ptr *dst_coef_arrays)
+/* Transpose source into destination */
+{
+  JDIMENSION dst_blk_x, dst_blk_y;
+  int ci, i, j, offset_x, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  /* Transposing pixels within a block just requires transposing the
+   * DCT coefficients.
+   * Partial iMCUs at the edges require no special treatment; we simply
+   * process all the available DCT blocks for every component.
+   */
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+	 dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+	     dst_blk_x += compptr->h_samp_factor) {
+	  src_buffer = (*srcinfo->mem->access_virt_barray)
+	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
+	     (JDIMENSION) compptr->h_samp_factor, FALSE);
+	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+	    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
+	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+	    for (i = 0; i < DCTSIZE; i++)
+	      for (j = 0; j < DCTSIZE; j++)
+		dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+	  }
+	}
+      }
+    }
+  }
+}
+
+
+static void
+do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	   jvirt_barray_ptr *src_coef_arrays,
+	   jvirt_barray_ptr *dst_coef_arrays)
+/* 90 degree rotation is equivalent to
+ *   1. Transposing the image;
+ *   2. Horizontal mirroring.
+ * These two steps are merged into a single processing routine.
+ */
+{
+  JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
+  int ci, i, j, offset_x, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  /* Because of the horizontal mirror step, we can't process partial iMCUs
+   * at the (output) right edge properly.  They just get transposed and
+   * not mirrored.
+   */
+  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_width = MCU_cols * compptr->h_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+	 dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+	     dst_blk_x += compptr->h_samp_factor) {
+	  src_buffer = (*srcinfo->mem->access_virt_barray)
+	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
+	     (JDIMENSION) compptr->h_samp_factor, FALSE);
+	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+	    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
+	    if (dst_blk_x < comp_width) {
+	      /* Block is within the mirrorable area. */
+	      dst_ptr = dst_buffer[offset_y]
+		[comp_width - dst_blk_x - offset_x - 1];
+	      for (i = 0; i < DCTSIZE; i++) {
+		for (j = 0; j < DCTSIZE; j++)
+		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+		i++;
+		for (j = 0; j < DCTSIZE; j++)
+		  dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+	      }
+	    } else {
+	      /* Edge blocks are transposed but not mirrored. */
+	      dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+	      for (i = 0; i < DCTSIZE; i++)
+		for (j = 0; j < DCTSIZE; j++)
+		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+	    }
+	  }
+	}
+      }
+    }
+  }
+}
+
+
+static void
+do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	    jvirt_barray_ptr *src_coef_arrays,
+	    jvirt_barray_ptr *dst_coef_arrays)
+/* 270 degree rotation is equivalent to
+ *   1. Horizontal mirroring;
+ *   2. Transposing the image.
+ * These two steps are merged into a single processing routine.
+ */
+{
+  JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
+  int ci, i, j, offset_x, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  /* Because of the horizontal mirror step, we can't process partial iMCUs
+   * at the (output) bottom edge properly.  They just get transposed and
+   * not mirrored.
+   */
+  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_height = MCU_rows * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+	 dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+	     dst_blk_x += compptr->h_samp_factor) {
+	  src_buffer = (*srcinfo->mem->access_virt_barray)
+	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
+	     (JDIMENSION) compptr->h_samp_factor, FALSE);
+	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+	    if (dst_blk_y < comp_height) {
+	      /* Block is within the mirrorable area. */
+	      src_ptr = src_buffer[offset_x]
+		[comp_height - dst_blk_y - offset_y - 1];
+	      for (i = 0; i < DCTSIZE; i++) {
+		for (j = 0; j < DCTSIZE; j++) {
+		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+		  j++;
+		  dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+		}
+	      }
+	    } else {
+	      /* Edge blocks are transposed but not mirrored. */
+	      src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
+	      for (i = 0; i < DCTSIZE; i++)
+		for (j = 0; j < DCTSIZE; j++)
+		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+	    }
+	  }
+	}
+      }
+    }
+  }
+}
+
+
+static void
+do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	    jvirt_barray_ptr *src_coef_arrays,
+	    jvirt_barray_ptr *dst_coef_arrays)
+/* 180 degree rotation is equivalent to
+ *   1. Vertical mirroring;
+ *   2. Horizontal mirroring.
+ * These two steps are merged into a single processing routine.
+ */
+{
+  JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
+  int ci, i, j, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JBLOCKROW src_row_ptr, dst_row_ptr;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
+  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_width = MCU_cols * compptr->h_samp_factor;
+    comp_height = MCU_rows * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+	 dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
+      if (dst_blk_y < comp_height) {
+	/* Row is within the vertically mirrorable area. */
+	src_buffer = (*srcinfo->mem->access_virt_barray)
+	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	   comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
+	   (JDIMENSION) compptr->v_samp_factor, FALSE);
+      } else {
+	/* Bottom-edge rows are only mirrored horizontally. */
+	src_buffer = (*srcinfo->mem->access_virt_barray)
+	  ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
+	   (JDIMENSION) compptr->v_samp_factor, FALSE);
+      }
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+	if (dst_blk_y < comp_height) {
+	  /* Row is within the mirrorable area. */
+	  dst_row_ptr = dst_buffer[offset_y];
+	  src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
+	  /* Process the blocks that can be mirrored both ways. */
+	  for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
+	    dst_ptr = dst_row_ptr[dst_blk_x];
+	    src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
+	    for (i = 0; i < DCTSIZE; i += 2) {
+	      /* For even row, negate every odd column. */
+	      for (j = 0; j < DCTSIZE; j += 2) {
+		*dst_ptr++ = *src_ptr++;
+		*dst_ptr++ = - *src_ptr++;
+	      }
+	      /* For odd row, negate every even column. */
+	      for (j = 0; j < DCTSIZE; j += 2) {
+		*dst_ptr++ = - *src_ptr++;
+		*dst_ptr++ = *src_ptr++;
+	      }
+	    }
+	  }
+	  /* Any remaining right-edge blocks are only mirrored vertically. */
+	  for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
+	    dst_ptr = dst_row_ptr[dst_blk_x];
+	    src_ptr = src_row_ptr[dst_blk_x];
+	    for (i = 0; i < DCTSIZE; i += 2) {
+	      for (j = 0; j < DCTSIZE; j++)
+		*dst_ptr++ = *src_ptr++;
+	      for (j = 0; j < DCTSIZE; j++)
+		*dst_ptr++ = - *src_ptr++;
+	    }
+	  }
+	} else {
+	  /* Remaining rows are just mirrored horizontally. */
+	  dst_row_ptr = dst_buffer[offset_y];
+	  src_row_ptr = src_buffer[offset_y];
+	  /* Process the blocks that can be mirrored. */
+	  for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
+	    dst_ptr = dst_row_ptr[dst_blk_x];
+	    src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
+	    for (i = 0; i < DCTSIZE2; i += 2) {
+	      *dst_ptr++ = *src_ptr++;
+	      *dst_ptr++ = - *src_ptr++;
+	    }
+	  }
+	  /* Any remaining right-edge blocks are only copied. */
+	  for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
+	    dst_ptr = dst_row_ptr[dst_blk_x];
+	    src_ptr = src_row_ptr[dst_blk_x];
+	    for (i = 0; i < DCTSIZE2; i++)
+	      *dst_ptr++ = *src_ptr++;
+	  }
+	}
+      }
+    }
+  }
+}
+
+
+static void
+do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	       jvirt_barray_ptr *src_coef_arrays,
+	       jvirt_barray_ptr *dst_coef_arrays)
+/* Transverse transpose is equivalent to
+ *   1. 180 degree rotation;
+ *   2. Transposition;
+ * or
+ *   1. Horizontal mirroring;
+ *   2. Transposition;
+ *   3. Horizontal mirroring.
+ * These steps are merged into a single processing routine.
+ */
+{
+  JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
+  int ci, i, j, offset_x, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
+  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_width = MCU_cols * compptr->h_samp_factor;
+    comp_height = MCU_rows * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+	 dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+	     dst_blk_x += compptr->h_samp_factor) {
+	  src_buffer = (*srcinfo->mem->access_virt_barray)
+	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
+	     (JDIMENSION) compptr->h_samp_factor, FALSE);
+	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+	    if (dst_blk_y < comp_height) {
+	      src_ptr = src_buffer[offset_x]
+		[comp_height - dst_blk_y - offset_y - 1];
+	      if (dst_blk_x < comp_width) {
+		/* Block is within the mirrorable area. */
+		dst_ptr = dst_buffer[offset_y]
+		  [comp_width - dst_blk_x - offset_x - 1];
+		for (i = 0; i < DCTSIZE; i++) {
+		  for (j = 0; j < DCTSIZE; j++) {
+		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+		    j++;
+		    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+		  }
+		  i++;
+		  for (j = 0; j < DCTSIZE; j++) {
+		    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+		    j++;
+		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+		  }
+		}
+	      } else {
+		/* Right-edge blocks are mirrored in y only */
+		dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+		for (i = 0; i < DCTSIZE; i++) {
+		  for (j = 0; j < DCTSIZE; j++) {
+		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+		    j++;
+		    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+		  }
+		}
+	      }
+	    } else {
+	      src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
+	      if (dst_blk_x < comp_width) {
+		/* Bottom-edge blocks are mirrored in x only */
+		dst_ptr = dst_buffer[offset_y]
+		  [comp_width - dst_blk_x - offset_x - 1];
+		for (i = 0; i < DCTSIZE; i++) {
+		  for (j = 0; j < DCTSIZE; j++)
+		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+		  i++;
+		  for (j = 0; j < DCTSIZE; j++)
+		    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+		}
+	      } else {
+		/* At lower right corner, just transpose, no mirroring */
+		dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+		for (i = 0; i < DCTSIZE; i++)
+		  for (j = 0; j < DCTSIZE; j++)
+		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+	      }
+	    }
+	  }
+	}
+      }
+    }
+  }
+}
+
+
+/* Request any required workspace.
+ *
+ * We allocate the workspace virtual arrays from the source decompression
+ * object, so that all the arrays (both the original data and the workspace)
+ * will be taken into account while making memory management decisions.
+ * Hence, this routine must be called after jpeg_read_header (which reads
+ * the image dimensions) and before jpeg_read_coefficients (which realizes
+ * the source's virtual arrays).
+ */
+
+void
+jtransform_request_workspace (j_decompress_ptr srcinfo,
+			      jpeg_transform_info *info)
+{
+  jvirt_barray_ptr *coef_arrays = NULL;
+  jpeg_component_info *compptr;
+  int ci;
+
+  if (info->force_grayscale &&
+      srcinfo->jpeg_color_space == JCS_YCbCr &&
+      srcinfo->num_components == 3) {
+    /* We'll only process the first component */
+    info->num_components = 1;
+  } else {
+    /* Process all the components */
+    info->num_components = srcinfo->num_components;
+  }
+
+  switch (info->transform) {
+  case JXFORM_NONE:
+  case JXFORM_FLIP_H:
+    /* Don't need a workspace array */
+    break;
+  case JXFORM_FLIP_V:
+  case JXFORM_ROT_180:
+    /* Need workspace arrays having same dimensions as source image.
+     * Note that we allocate arrays padded out to the next iMCU boundary,
+     * so that transform routines need not worry about missing edge blocks.
+     */
+    coef_arrays = (jvirt_barray_ptr *)
+      (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
+	sizeof(jvirt_barray_ptr) * info->num_components);
+    for (ci = 0; ci < info->num_components; ci++) {
+      compptr = srcinfo->comp_info + ci;
+      coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
+	((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
+	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+				(long) compptr->h_samp_factor),
+	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+				(long) compptr->v_samp_factor),
+	 (JDIMENSION) compptr->v_samp_factor);
+    }
+    break;
+  case JXFORM_TRANSPOSE:
+  case JXFORM_TRANSVERSE:
+  case JXFORM_ROT_90:
+  case JXFORM_ROT_270:
+    /* Need workspace arrays having transposed dimensions.
+     * Note that we allocate arrays padded out to the next iMCU boundary,
+     * so that transform routines need not worry about missing edge blocks.
+     */
+    coef_arrays = (jvirt_barray_ptr *)
+      (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
+	sizeof(jvirt_barray_ptr) * info->num_components);
+    for (ci = 0; ci < info->num_components; ci++) {
+      compptr = srcinfo->comp_info + ci;
+      coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
+	((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
+	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+				(long) compptr->v_samp_factor),
+	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+				(long) compptr->h_samp_factor),
+	 (JDIMENSION) compptr->h_samp_factor);
+    }
+    break;
+  }
+  info->workspace_coef_arrays = coef_arrays;
+}
+
+
+/* Transpose destination image parameters */
+
+static void
+transpose_critical_parameters (j_compress_ptr dstinfo)
+{
+  int tblno, i, j, ci, itemp;
+  jpeg_component_info *compptr;
+  JQUANT_TBL *qtblptr;
+  JDIMENSION dtemp;
+  UINT16 qtemp;
+
+  /* Transpose basic image dimensions */
+  dtemp = dstinfo->image_width;
+  dstinfo->image_width = dstinfo->image_height;
+  dstinfo->image_height = dtemp;
+
+  /* Transpose sampling factors */
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    itemp = compptr->h_samp_factor;
+    compptr->h_samp_factor = compptr->v_samp_factor;
+    compptr->v_samp_factor = itemp;
+  }
+
+  /* Transpose quantization tables */
+  for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
+    qtblptr = dstinfo->quant_tbl_ptrs[tblno];
+    if (qtblptr != NULL) {
+      for (i = 0; i < DCTSIZE; i++) {
+	for (j = 0; j < i; j++) {
+	  qtemp = qtblptr->quantval[i*DCTSIZE+j];
+	  qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i];
+	  qtblptr->quantval[j*DCTSIZE+i] = qtemp;
+	}
+      }
+    }
+  }
+}
+
+
+/* Trim off any partial iMCUs on the indicated destination edge */
+
+static void
+trim_right_edge (j_compress_ptr dstinfo)
+{
+  int ci, max_h_samp_factor;
+  JDIMENSION MCU_cols;
+
+  /* We have to compute max_h_samp_factor ourselves,
+   * because it hasn't been set yet in the destination
+   * (and we don't want to use the source's value).
+   */
+  max_h_samp_factor = 1;
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor;
+    max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor);
+  }
+  MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE);
+  if (MCU_cols > 0)		/* can't trim to 0 pixels */
+    dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE);
+}
+
+static void
+trim_bottom_edge (j_compress_ptr dstinfo)
+{
+  int ci, max_v_samp_factor;
+  JDIMENSION MCU_rows;
+
+  /* We have to compute max_v_samp_factor ourselves,
+   * because it hasn't been set yet in the destination
+   * (and we don't want to use the source's value).
+   */
+  max_v_samp_factor = 1;
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor;
+    max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor);
+  }
+  MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE);
+  if (MCU_rows > 0)		/* can't trim to 0 pixels */
+    dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE);
+}
+
+
+/* Adjust output image parameters as needed.
+ *
+ * This must be called after jpeg_copy_critical_parameters()
+ * and before jpeg_write_coefficients().
+ *
+ * The return value is the set of virtual coefficient arrays to be written
+ * (either the ones allocated by jtransform_request_workspace, or the
+ * original source data arrays).  The caller will need to pass this value
+ * to jpeg_write_coefficients().
+ */
+
+jvirt_barray_ptr *
+jtransform_adjust_parameters (j_decompress_ptr srcinfo,
+			      j_compress_ptr dstinfo,
+			      jvirt_barray_ptr *src_coef_arrays,
+			      jpeg_transform_info *info)
+{
+  /* If force-to-grayscale is requested, adjust destination parameters */
+  if (info->force_grayscale) {
+    /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
+     * properly.  Among other things, the target h_samp_factor & v_samp_factor
+     * will get set to 1, which typically won't match the source.
+     * In fact we do this even if the source is already grayscale; that
+     * provides an easy way of coercing a grayscale JPEG with funny sampling
+     * factors to the customary 1,1.  (Some decoders fail on other factors.)
+     */
+    if ((dstinfo->jpeg_color_space == JCS_YCbCr &&
+	 dstinfo->num_components == 3) ||
+	(dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
+	 dstinfo->num_components == 1)) {
+      /* We have to preserve the source's quantization table number. */
+      int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
+      jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
+      dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
+    } else {
+      /* Sorry, can't do it */
+      ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
+    }
+  }
+
+  /* Correct the destination's image dimensions etc if necessary */
+  switch (info->transform) {
+  case JXFORM_NONE:
+    /* Nothing to do */
+    break;
+  case JXFORM_FLIP_H:
+    if (info->trim)
+      trim_right_edge(dstinfo);
+    break;
+  case JXFORM_FLIP_V:
+    if (info->trim)
+      trim_bottom_edge(dstinfo);
+    break;
+  case JXFORM_TRANSPOSE:
+    transpose_critical_parameters(dstinfo);
+    /* transpose does NOT have to trim anything */
+    break;
+  case JXFORM_TRANSVERSE:
+    transpose_critical_parameters(dstinfo);
+    if (info->trim) {
+      trim_right_edge(dstinfo);
+      trim_bottom_edge(dstinfo);
+    }
+    break;
+  case JXFORM_ROT_90:
+    transpose_critical_parameters(dstinfo);
+    if (info->trim)
+      trim_right_edge(dstinfo);
+    break;
+  case JXFORM_ROT_180:
+    if (info->trim) {
+      trim_right_edge(dstinfo);
+      trim_bottom_edge(dstinfo);
+    }
+    break;
+  case JXFORM_ROT_270:
+    transpose_critical_parameters(dstinfo);
+    if (info->trim)
+      trim_bottom_edge(dstinfo);
+    break;
+  }
+
+  /* Return the appropriate output data set */
+  if (info->workspace_coef_arrays != NULL)
+    return info->workspace_coef_arrays;
+  return src_coef_arrays;
+}
+
+
+/* Execute the actual transformation, if any.
+ *
+ * This must be called *after* jpeg_write_coefficients, because it depends
+ * on jpeg_write_coefficients to have computed subsidiary values such as
+ * the per-component width and height fields in the destination object.
+ *
+ * Note that some transformations will modify the source data arrays!
+ */
+
+void
+jtransform_execute_transformation (j_decompress_ptr srcinfo,
+				   j_compress_ptr dstinfo,
+				   jvirt_barray_ptr *src_coef_arrays,
+				   jpeg_transform_info *info)
+{
+  jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
+
+  switch (info->transform) {
+  case JXFORM_NONE:
+    break;
+  case JXFORM_FLIP_H:
+    do_flip_h(srcinfo, dstinfo, src_coef_arrays);
+    break;
+  case JXFORM_FLIP_V:
+    do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    break;
+  case JXFORM_TRANSPOSE:
+    do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    break;
+  case JXFORM_TRANSVERSE:
+    do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    break;
+  case JXFORM_ROT_90:
+    do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    break;
+  case JXFORM_ROT_180:
+    do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    break;
+  case JXFORM_ROT_270:
+    do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    break;
+  }
+}
+
+
+/* Setup decompression object to save desired markers in memory.
+ * This must be called before jpeg_read_header() to have the desired effect.
+ */
+
+void
+jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option)
+{
+#ifdef SAVE_MARKERS_SUPPORTED
+  int m;
+
+  /* Save comments except under NONE option */
+  if (option != JCOPYOPT_NONE) {
+    jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
+  }
+  /* Save all types of APPn markers iff ALL option */
+  if (option == JCOPYOPT_ALL) {
+    for (m = 0; m < 16; m++)
+      jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
+  }
+#endif /* SAVE_MARKERS_SUPPORTED */
+}
+
+/* Copy markers saved in the given source object to the destination object.
+ * This should be called just after jpeg_start_compress() or
+ * jpeg_write_coefficients().
+ * Note that those routines will have written the SOI, and also the
+ * JFIF APP0 or Adobe APP14 markers if selected.
+ */
+
+void
+jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+		       JCOPY_OPTION option)
+{
+  jpeg_saved_marker_ptr marker;
+
+  /* In the current implementation, we don't actually need to examine the
+   * option flag here; we just copy everything that got saved.
+   * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
+   * if the encoder library already wrote one.
+   */
+  for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
+    if (dstinfo->write_JFIF_header &&
+	marker->marker == JPEG_APP0 &&
+	marker->data_length >= 5 &&
+	GETJOCTET(marker->data[0]) == 0x4A &&
+	GETJOCTET(marker->data[1]) == 0x46 &&
+	GETJOCTET(marker->data[2]) == 0x49 &&
+	GETJOCTET(marker->data[3]) == 0x46 &&
+	GETJOCTET(marker->data[4]) == 0)
+      continue;			/* reject duplicate JFIF */
+    if (dstinfo->write_Adobe_marker &&
+	marker->marker == JPEG_APP0+14 &&
+	marker->data_length >= 5 &&
+	GETJOCTET(marker->data[0]) == 0x41 &&
+	GETJOCTET(marker->data[1]) == 0x64 &&
+	GETJOCTET(marker->data[2]) == 0x6F &&
+	GETJOCTET(marker->data[3]) == 0x62 &&
+	GETJOCTET(marker->data[4]) == 0x65)
+      continue;			/* reject duplicate Adobe */
+
+#ifdef NEED_FAR_POINTERS
+    /* We could use jpeg_write_marker if the data weren't FAR... */
+    {
+      unsigned int i;
+      jpeg_write_m_header(dstinfo, marker->marker, marker->data_length);
+      for (i = 0; i < marker->data_length; i++)
+	jpeg_write_m_byte(dstinfo, marker->data[i]);
+    }
+#else
+    jpeg_write_marker(dstinfo, marker->marker,
+		      marker->data, marker->data_length);
+#endif
+  }
+}
+
+
+#endif /* HAVE_LIBJPEG */
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/4.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/4.html new file mode 100644 index 0000000..d823299 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/4.html @@ -0,0 +1,584 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
/*
+ * transupp.h
+ *
+ * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains declarations for image transformation routines and
+ * other utility code used by the jpegtran sample application.  These are
+ * NOT part of the core JPEG library.  But we keep these routines separate
+ * from jpegtran.c to ease the task of maintaining jpegtran-like programs
+ * that have other user interfaces.
+ *
+ * NOTE: all the routines declared here have very specific requirements
+ * about when they are to be executed during the reading and writing of the
+ * source and destination files.  See the comments in transupp.c, or see
+ * jpegtran.c for an example of correct usage.
+ */
+
+/* If you happen not to want the image transform support, disable it here */
+#ifndef TRANSFORMS_SUPPORTED
+#define TRANSFORMS_SUPPORTED 1		/* 0 disables transform code */
+#endif
+
+/*
+ * Although rotating and flipping data expressed as DCT coefficients is not
+ * hard, there is an asymmetry in the JPEG format specification for images
+ * whose dimensions aren't multiples of the iMCU size.  The right and bottom
+ * image edges are padded out to the next iMCU boundary with junk data; but
+ * no padding is possible at the top and left edges.  If we were to flip
+ * the whole image including the pad data, then pad garbage would become
+ * visible at the top and/or left, and real pixels would disappear into the
+ * pad margins --- perhaps permanently, since encoders & decoders may not
+ * bother to preserve DCT blocks that appear to be completely outside the
+ * nominal image area.  So, we have to exclude any partial iMCUs from the
+ * basic transformation.
+ *
+ * Transpose is the only transformation that can handle partial iMCUs at the
+ * right and bottom edges completely cleanly.  flip_h can flip partial iMCUs
+ * at the bottom, but leaves any partial iMCUs at the right edge untouched.
+ * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched.
+ * The other transforms are defined as combinations of these basic transforms
+ * and process edge blocks in a way that preserves the equivalence.
+ *
+ * The "trim" option causes untransformable partial iMCUs to be dropped;
+ * this is not strictly lossless, but it usually gives the best-looking
+ * result for odd-size images.  Note that when this option is active,
+ * the expected mathematical equivalences between the transforms may not hold.
+ * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim
+ * followed by -rot 180 -trim trims both edges.)
+ *
+ * We also offer a lossless-crop option, which discards data outside a given
+ * image region but losslessly preserves what is inside.  Like the rotate and
+ * flip transforms, lossless crop is restricted by the JPEG format: the upper
+ * left corner of the selected region must fall on an iMCU boundary.  If this
+ * does not hold for the given crop parameters, we silently move the upper left
+ * corner up and/or left to make it so, simultaneously increasing the region
+ * dimensions to keep the lower right crop corner unchanged.  (Thus, the
+ * output image covers at least the requested region, but may cover more.)
+ *
+ * We also provide a lossless-resize option, which is kind of a lossless-crop
+ * operation in the DCT coefficient block domain - it discards higher-order
+ * coefficients and losslessly preserves lower-order coefficients of a
+ * sub-block.
+ *
+ * Rotate/flip transform, resize, and crop can be requested together in a
+ * single invocation.  The crop is applied last --- that is, the crop region
+ * is specified in terms of the destination image after transform/resize.
+ *
+ * We also offer a "force to grayscale" option, which simply discards the
+ * chrominance channels of a YCbCr image.  This is lossless in the sense that
+ * the luminance channel is preserved exactly.  It's not the same kind of
+ * thing as the rotate/flip transformations, but it's convenient to handle it
+ * as part of this package, mainly because the transformation routines have to
+ * be aware of the option to know how many components to work on.
+ */
+
+#ifndef TRANSUPP_H
+#define TRANSUPP_H
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jtransform_parse_crop_spec	jTrParCrop
+#define jtransform_request_workspace	jTrRequest
+#define jtransform_adjust_parameters	jTrAdjust
+#define jtransform_execute_transform	jTrExec
+#define jtransform_perfect_transform	jTrPerfect
+#define jcopy_markers_setup		jCMrkSetup
+#define jcopy_markers_execute		jCMrkExec
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/*
+ * Codes for supported types of image transformations.
+ */
+
+typedef enum {
+	JXFORM_NONE,		/* no transformation */
+	JXFORM_FLIP_H,		/* horizontal flip */
+	JXFORM_FLIP_V,		/* vertical flip */
+	JXFORM_TRANSPOSE,	/* transpose across UL-to-LR axis */
+	JXFORM_TRANSVERSE,	/* transpose across UR-to-LL axis */
+	JXFORM_ROT_90,		/* 90-degree clockwise rotation */
+	JXFORM_ROT_180,		/* 180-degree rotation */
+	JXFORM_ROT_270		/* 270-degree clockwise (or 90 ccw) */
+} JXFORM_CODE;
+
+/*
+ * Codes for crop parameters, which can individually be unspecified,
+ * positive, or negative.  (Negative width or height makes no sense, though.)
+ */
+
+typedef enum {
+	JCROP_UNSET,
+	JCROP_POS,
+	JCROP_NEG
+} JCROP_CODE;
+
+/*
+ * Transform parameters struct.
+ * NB: application must not change any elements of this struct after
+ * calling jtransform_request_workspace.
+ */
+
+typedef struct {
+  /* Options: set by caller */
+  JXFORM_CODE transform;	/* image transform operator */
+  boolean perfect;		/* if TRUE, fail if partial MCUs are requested */
+  boolean trim;			/* if TRUE, trim partial MCUs as needed */
+  boolean force_grayscale;	/* if TRUE, convert color image to grayscale */
+  boolean crop;			/* if TRUE, crop source image */
+
+  /* Crop parameters: application need not set these unless crop is TRUE.
+   * These can be filled in by jtransform_parse_crop_spec().
+   */
+  JDIMENSION crop_width;	/* Width of selected region */
+  JCROP_CODE crop_width_set;
+  JDIMENSION crop_height;	/* Height of selected region */
+  JCROP_CODE crop_height_set;
+  JDIMENSION crop_xoffset;	/* X offset of selected region */
+  JCROP_CODE crop_xoffset_set;	/* (negative measures from right edge) */
+  JDIMENSION crop_yoffset;	/* Y offset of selected region */
+  JCROP_CODE crop_yoffset_set;	/* (negative measures from bottom edge) */
+
+  /* Internal workspace: caller should not touch these */
+  int num_components;		/* # of components in workspace */
+  jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */
+  JDIMENSION output_width;	/* cropped destination dimensions */
+  JDIMENSION output_height;
+  JDIMENSION x_crop_offset;	/* destination crop offsets measured in iMCUs */
+  JDIMENSION y_crop_offset;
+  int iMCU_sample_width;	/* destination iMCU size */
+  int iMCU_sample_height;
+} jpeg_transform_info;
+
+
+#if TRANSFORMS_SUPPORTED
+
+/* Parse a crop specification (written in X11 geometry style) */
+EXTERN(boolean) jtransform_parse_crop_spec<--- There is an unknown macro here somewhere. Configuration is required. If EXTERN is a macro then please configure it.
+	JPP((jpeg_transform_info *info, const char *spec));
+/* Request any required workspace */
+EXTERN(boolean) jtransform_request_workspace
+	JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info));
+/* Adjust output image parameters */
+EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters
+	JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	     jvirt_barray_ptr *src_coef_arrays,
+	     jpeg_transform_info *info));
+/* Execute the actual transformation, if any */
+EXTERN(void) jtransform_execute_transform
+	JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	     jvirt_barray_ptr *src_coef_arrays,
+	     jpeg_transform_info *info));
+/* Determine whether lossless transformation is perfectly
+ * possible for a specified image and transformation.
+ */
+EXTERN(boolean) jtransform_perfect_transform
+	JPP((JDIMENSION image_width, JDIMENSION image_height,
+	     int MCU_width, int MCU_height,
+	     JXFORM_CODE transform));
+
+/* jtransform_execute_transform used to be called
+ * jtransform_execute_transformation, but some compilers complain about
+ * routine names that long.  This macro is here to avoid breaking any
+ * old source code that uses the original name...
+ */
+#define jtransform_execute_transformation	jtransform_execute_transform
+
+#endif /* TRANSFORMS_SUPPORTED */
+
+
+/*
+ * Support for copying optional markers from source to destination file.
+ */
+
+typedef enum {
+	JCOPYOPT_NONE,		/* copy no optional markers */
+	JCOPYOPT_COMMENTS,	/* copy only comment (COM) markers */
+	JCOPYOPT_ALL		/* copy all optional markers */
+} JCOPY_OPTION;
+
+#define JCOPYOPT_DEFAULT  JCOPYOPT_COMMENTS	/* recommended default */
+
+/* Setup decompression object to save desired markers in memory */
+EXTERN(void) jcopy_markers_setup
+	JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option));
+/* Copy markers saved in the given source object to the destination object */
+EXTERN(void) jcopy_markers_execute
+	JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	     JCOPY_OPTION option));
+
+#endif /* TRANSUPP_H */
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/5.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/5.html new file mode 100644 index 0000000..d7e64fe --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/5.html @@ -0,0 +1,1544 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
/*
+ * eom-close-confirmation-dialog.c
+ * This file is part of eom
+ *
+ * Author: Marcus Carlson <marcus@mejlamej.nu>
+ *
+ * Based on gedit code (gedit/gedit-close-confirmation.c) by gedit Team
+ *
+ * Copyright (C) 2004-2009 GNOME Foundation
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+
+#include "eom-close-confirmation-dialog.h"
+#include <eom-window.h>
+
+/* Properties */
+enum
+{
+	PROP_0,
+	PROP_UNSAVED_IMAGES
+};
+
+/* Mode */
+enum
+{
+	SINGLE_IMG_MODE,
+	MULTIPLE_IMGS_MODE
+};
+
+/* Columns */
+enum
+{
+	SAVE_COLUMN,
+	IMAGE_COLUMN,
+	NAME_COLUMN,
+	IMG_COLUMN, /* a handy pointer to the image */
+	N_COLUMNS
+};
+
+struct _EomCloseConfirmationDialogPrivate
+{
+	GList       *unsaved_images;
+
+	GList       *selected_images;
+
+	GtkTreeModel *list_store;
+	GtkCellRenderer *toggle_renderer;
+};
+
+#define GET_MODE(priv) (((priv->unsaved_images != NULL) && \
+			 (priv->unsaved_images->next == NULL)) ? \
+			  SINGLE_IMG_MODE : MULTIPLE_IMGS_MODE)
+
+#define IMAGE_COLUMN_HEIGHT 40
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomCloseConfirmationDialog, eom_close_confirmation_dialog, GTK_TYPE_DIALOG)
+
+static void 	 set_unsaved_image 		(EomCloseConfirmationDialog *dlg,
+						 const GList                  *list);
+
+static GList 	*get_selected_imgs 		(GtkTreeModel                 *store);
+
+static GdkPixbuf *
+eom_close_confirmation_dialog_get_icon (const gchar *icon_name)
+{
+	GError *error = NULL;
+	GtkIconTheme *icon_theme;
+	GdkPixbuf *pixbuf;
+
+	icon_theme = gtk_icon_theme_get_default ();
+
+	pixbuf = gtk_icon_theme_load_icon (icon_theme,
+					   icon_name,
+					   IMAGE_COLUMN_HEIGHT,
+					   0,
+					   &error);
+
+	if (!pixbuf) {
+		g_warning ("Couldn't load icon: %s", error->message);
+		g_error_free (error);
+	}
+
+	return pixbuf;
+}
+
+static GdkPixbuf*
+get_nothumb_pixbuf (void)
+{
+	static GOnce nothumb_once = G_ONCE_INIT;
+	g_once (&nothumb_once, (GThreadFunc) eom_close_confirmation_dialog_get_icon, "image-x-generic");
+	return GDK_PIXBUF (g_object_ref (nothumb_once.retval));
+}
+
+/*  Since we connect in the costructor we are sure this handler will be called
+ *  before the user ones
+ */
+static void
+response_cb (EomCloseConfirmationDialog *dlg,
+             gint                        response_id,
+             gpointer                    data)
+{
+	EomCloseConfirmationDialogPrivate *priv;
+
+	g_return_if_fail (EOM_IS_CLOSE_CONFIRMATION_DIALOG (dlg));
+
+	priv = dlg->priv;
+
+	if (priv->selected_images != NULL)
+		g_list_free (priv->selected_images);
+
+	if (response_id == GTK_RESPONSE_YES)
+	{
+		if (GET_MODE (priv) == SINGLE_IMG_MODE)
+		{
+			priv->selected_images =
+				g_list_copy (priv->unsaved_images);
+		}
+		else
+		{
+			g_return_if_fail (priv->list_store);
+
+			priv->selected_images =
+				get_selected_imgs (priv->list_store);
+		}
+	}
+	else
+		priv->selected_images = NULL;
+}
+
+static void
+add_buttons (EomCloseConfirmationDialog *dlg)
+{
+	gtk_dialog_add_button (GTK_DIALOG (dlg),
+			       _("Close _without Saving"),
+			       GTK_RESPONSE_NO);
+
+	gtk_dialog_add_button (GTK_DIALOG (dlg),
+			       "gtk-cancel", GTK_RESPONSE_CANCEL);
+
+	gtk_dialog_add_button (GTK_DIALOG (dlg),
+			       "gtk-save",
+			       GTK_RESPONSE_YES);
+
+	gtk_dialog_set_default_response	(GTK_DIALOG (dlg),
+					 GTK_RESPONSE_YES);
+}
+
+static void
+eom_close_confirmation_dialog_init (EomCloseConfirmationDialog *dlg)
+{
+	AtkObject *atk_obj;
+
+	dlg->priv = eom_close_confirmation_dialog_get_instance_private (dlg);
+
+	gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
+	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), 14);
+	gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
+	gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dlg), TRUE);
+
+	gtk_window_set_title (GTK_WINDOW (dlg), "");
+
+	gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
+	gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
+
+	atk_obj = gtk_widget_get_accessible (GTK_WIDGET (dlg));
+	atk_object_set_role (atk_obj, ATK_ROLE_ALERT);
+	atk_object_set_name (atk_obj, _("Question"));
+
+	g_signal_connect (dlg,
+			  "response",
+			  G_CALLBACK (response_cb),
+			  NULL);
+}
+
+static void
+eom_close_confirmation_dialog_finalize (GObject *object)
+{
+	EomCloseConfirmationDialogPrivate *priv;
+
+	priv = EOM_CLOSE_CONFIRMATION_DIALOG (object)->priv;
+
+	if (priv->unsaved_images != NULL)
+		g_list_free (priv->unsaved_images);
+
+	if (priv->selected_images != NULL)
+		g_list_free (priv->selected_images);
+
+	/* Call the parent's destructor */
+	G_OBJECT_CLASS (eom_close_confirmation_dialog_parent_class)->finalize (object);
+}
+
+static void
+eom_close_confirmation_dialog_set_property (GObject      *object,
+					      guint         prop_id,
+					      const GValue *value,
+					      GParamSpec   *pspec)
+{
+	EomCloseConfirmationDialog *dlg;
+
+	dlg = EOM_CLOSE_CONFIRMATION_DIALOG (object);
+
+	switch (prop_id)
+	{
+		case PROP_UNSAVED_IMAGES:
+			set_unsaved_image (dlg, g_value_get_pointer (value));
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+eom_close_confirmation_dialog_get_property (GObject    *object,
+					      guint       prop_id,
+					      GValue     *value,
+					      GParamSpec *pspec)
+{
+	EomCloseConfirmationDialogPrivate *priv;
+
+	priv = EOM_CLOSE_CONFIRMATION_DIALOG (object)->priv;
+
+	switch( prop_id )
+	{
+		case PROP_UNSAVED_IMAGES:
+			g_value_set_pointer (value, priv->unsaved_images);
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+eom_close_confirmation_dialog_class_init (EomCloseConfirmationDialogClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	gobject_class->set_property = eom_close_confirmation_dialog_set_property;
+	gobject_class->get_property = eom_close_confirmation_dialog_get_property;
+	gobject_class->finalize = eom_close_confirmation_dialog_finalize;
+
+	g_object_class_install_property (gobject_class,
+					 PROP_UNSAVED_IMAGES,
+					 g_param_spec_pointer ("unsaved_images",
+						 	       "Unsaved Images",
+							       "List of Unsaved Images",
+							       (G_PARAM_READWRITE |
+							        G_PARAM_CONSTRUCT_ONLY)));
+}
+
+static GList *
+get_selected_imgs (GtkTreeModel *store)
+{
+	GList       *list;
+	gboolean     valid;
+	GtkTreeIter  iter;
+
+	list = NULL;
+	valid = gtk_tree_model_get_iter_first (store, &iter);
+
+	while (valid)
+	{
+		gboolean to_save;
+		EomImage *img;
+
+		gtk_tree_model_get (store, &iter,
+				    SAVE_COLUMN, &to_save,
+				    IMG_COLUMN, &img,
+				    -1);
+		if (to_save)
+			list = g_list_prepend (list, img);
+
+		valid = gtk_tree_model_iter_next (store, &iter);
+	}
+
+	list = g_list_reverse (list);
+
+	return list;
+}
+
+GList *
+eom_close_confirmation_dialog_get_selected_images (EomCloseConfirmationDialog *dlg)
+{
+	g_return_val_if_fail (EOM_IS_CLOSE_CONFIRMATION_DIALOG (dlg), NULL);
+
+	return g_list_copy (dlg->priv->selected_images);
+}
+
+GtkWidget *
+eom_close_confirmation_dialog_new (GtkWindow *parent,
+				   GList     *unsaved_images)
+{
+	GtkWidget *dlg;
+	GtkWindowGroup *wg;
+
+	g_return_val_if_fail (unsaved_images != NULL, NULL);
+
+	dlg = GTK_WIDGET (g_object_new (EOM_TYPE_CLOSE_CONFIRMATION_DIALOG,
+				        "unsaved_images", unsaved_images,
+				        NULL));
+	g_return_val_if_fail (dlg != NULL, NULL);
+
+	if (parent != NULL)
+	{
+		wg = gtk_window_get_group (parent);
+
+		/* gtk_window_get_group returns a default group when the given
+		 * window doesn't have a group. Explicitly add the window to
+		 * the group here to make sure it's actually in the returned
+		 * group. It makes no difference if it is already. */
+		gtk_window_group_add_window (wg, parent);
+		gtk_window_group_add_window (wg, GTK_WINDOW (dlg));
+
+		gtk_window_set_transient_for (GTK_WINDOW (dlg), parent);
+	}
+
+	return dlg;
+}
+
+GtkWidget *
+eom_close_confirmation_dialog_new_single (GtkWindow     *parent,
+					  EomImage	*image)
+{
+	GtkWidget *dlg;
+	GList *unsaved_images;
+	g_return_val_if_fail (image != NULL, NULL);
+
+	unsaved_images = g_list_prepend (NULL, image);
+
+	dlg = eom_close_confirmation_dialog_new (parent,
+						 unsaved_images);
+
+	g_list_free (unsaved_images);
+
+	return dlg;
+}
+
+static gchar *
+get_text_secondary_label (EomImage *image)
+{
+	gchar *secondary_msg;
+
+	secondary_msg = g_strdup (_("If you don't save, your changes will be lost."));
+
+	return secondary_msg;
+}
+
+static void
+build_single_img_dialog (EomCloseConfirmationDialog *dlg)
+{
+	GtkWidget     *hbox;
+	GtkWidget     *vbox;
+	GtkWidget     *primary_label;
+	GtkWidget     *secondary_label;
+	GtkWidget     *image;
+	EomImage      *img;
+	const gchar   *image_name;
+	gchar         *str;
+	gchar         *markup_str;
+
+	g_return_if_fail (dlg->priv->unsaved_images->data != NULL);
+	img = EOM_IMAGE (dlg->priv->unsaved_images->data);
+
+	/* Image */
+	image = gtk_image_new_from_icon_name ("dialog-warning",
+					  GTK_ICON_SIZE_DIALOG);
+	gtk_widget_set_valign (image, GTK_ALIGN_START);
+
+	/* Primary label */
+	primary_label = gtk_label_new (NULL);
+	gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
+	gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
+	gtk_label_set_max_width_chars (GTK_LABEL (primary_label), 88);
+	gtk_label_set_xalign (GTK_LABEL (primary_label), 0.0);
+	gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
+
+	image_name = eom_image_get_caption (img);
+
+	str = g_markup_printf_escaped (_("Save changes to image \"%s\" before closing?"),
+				       image_name);
+	markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", str, "</span>", NULL);
+	g_free (str);
+
+	gtk_label_set_markup (GTK_LABEL (primary_label), markup_str);
+	g_free (markup_str);
+
+	/* Secondary label */
+	str = get_text_secondary_label (img);
+
+	secondary_label = gtk_label_new (str);
+	g_free (str);
+	gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
+	gtk_label_set_xalign (GTK_LABEL (secondary_label), 0.0);
+	gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
+
+	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+	gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+
+	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+
+	gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+
+	gtk_box_pack_start (GTK_BOX (vbox), primary_label, FALSE, FALSE, 0);
+
+	gtk_box_pack_start (GTK_BOX (vbox), secondary_label, FALSE, FALSE, 0);
+
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
+			    hbox,
+	                    FALSE,
+			    FALSE,
+			    0);
+
+	add_buttons (dlg);
+
+	gtk_widget_show_all (hbox);
+}
+
+static void
+populate_model (GtkTreeModel *store, GList *imgs)
+{
+	GtkTreeIter iter;
+
+	while (imgs != NULL)
+	{
+		EomImage *img;
+		const gchar *name;
+		GdkPixbuf *buf = NULL;
+		GdkPixbuf *buf_scaled = NULL;
+		int width;
+		double ratio;
+
+		img = EOM_IMAGE (imgs->data);
+
+		name = eom_image_get_caption (img);
+		buf = eom_image_get_thumbnail (img);
+
+		if (buf) {
+			ratio = IMAGE_COLUMN_HEIGHT / (double) gdk_pixbuf_get_height (buf);
+			width = (int) (gdk_pixbuf_get_width (buf) * ratio);
+			buf_scaled = gdk_pixbuf_scale_simple (buf, width, IMAGE_COLUMN_HEIGHT, GDK_INTERP_BILINEAR);
+		} else
+			buf_scaled = get_nothumb_pixbuf ();
+
+		gtk_list_store_append (GTK_LIST_STORE (store), &iter);
+		gtk_list_store_set (GTK_LIST_STORE (store), &iter,
+				    SAVE_COLUMN, TRUE,
+				    IMAGE_COLUMN, buf_scaled,
+				    NAME_COLUMN, name,
+				    IMG_COLUMN, img,
+			            -1);
+
+		imgs = g_list_next (imgs);
+		g_object_unref (buf_scaled);
+	}
+}
+
+static void
+save_toggled (GtkCellRendererToggle *renderer, gchar *path_str, GtkTreeModel *store)
+{
+	GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
+	GtkTreeIter iter;
+	gboolean active;
+
+	gtk_tree_model_get_iter (store, &iter, path);
+	gtk_tree_model_get (store, &iter, SAVE_COLUMN, &active, -1);
+
+	active ^= 1;
+
+	gtk_list_store_set (GTK_LIST_STORE (store), &iter,
+			    SAVE_COLUMN, active, -1);
+
+	gtk_tree_path_free (path);
+}
+
+static GtkWidget *
+create_treeview (EomCloseConfirmationDialogPrivate *priv)
+{
+	GtkListStore *store;
+	GtkWidget *treeview;
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+
+	treeview = gtk_tree_view_new ();
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
+	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), FALSE);
+
+	/* Create and populate the model */
+	store = gtk_list_store_new (N_COLUMNS, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
+	populate_model (GTK_TREE_MODEL (store), priv->unsaved_images);
+
+	/* Set model to the treeview */
+	gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
+	g_object_unref (store);
+
+	priv->list_store = GTK_TREE_MODEL (store);
+
+	/* Add columns */
+	priv->toggle_renderer = renderer = gtk_cell_renderer_toggle_new ();
+	g_signal_connect (renderer, "toggled",
+			  G_CALLBACK (save_toggled), store);
+
+	column = gtk_tree_view_column_new_with_attributes ("Save?",
+							   renderer,
+							   "active",
+							   SAVE_COLUMN,
+							   NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+	renderer = gtk_cell_renderer_pixbuf_new ();
+
+	column = gtk_tree_view_column_new_with_attributes ("Image",
+							   renderer,
+							   "pixbuf",
+							   IMAGE_COLUMN,
+							   NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+
+
+	renderer = gtk_cell_renderer_text_new ();
+	column = gtk_tree_view_column_new_with_attributes ("Name",
+							   renderer,
+							   "text",
+							   NAME_COLUMN,
+							   NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+	return treeview;
+}
+
+static void
+build_multiple_imgs_dialog (EomCloseConfirmationDialog *dlg)
+{
+	EomCloseConfirmationDialogPrivate *priv;
+	GtkWidget *hbox;
+	GtkWidget *image;
+	GtkWidget *vbox;
+	GtkWidget *primary_label;
+	GtkWidget *vbox2;
+	GtkWidget *select_label;
+	GtkWidget *scrolledwindow;
+	GtkWidget *treeview;
+	GtkWidget *secondary_label;
+	gchar     *str;
+	gchar     *markup_str;
+
+	priv = dlg->priv;
+
+	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+	gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+  	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
+			    hbox, TRUE, TRUE, 0);
+
+	/* Image */
+	image = gtk_image_new_from_icon_name ("dialog-warning",
+					  GTK_ICON_SIZE_DIALOG);
+	gtk_widget_set_valign (image, GTK_ALIGN_START);
+	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+	gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+
+	/* Primary label */
+	primary_label = gtk_label_new (NULL);
+	gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
+	gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
+	gtk_label_set_max_width_chars (GTK_LABEL (primary_label), 88);
+	gtk_label_set_xalign (GTK_LABEL (primary_label), 0.0);
+	gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
+
+	str = g_strdup_printf (
+			ngettext ("There is %d image with unsaved changes. "
+				  "Save changes before closing?",
+				  "There are %d images with unsaved changes. "
+				  "Save changes before closing?",
+				  g_list_length (priv->unsaved_images)),
+			g_list_length (priv->unsaved_images));
+
+	markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", str, "</span>", NULL);
+	g_free (str);
+
+	gtk_label_set_markup (GTK_LABEL (primary_label), markup_str);
+	g_free (markup_str);
+	gtk_box_pack_start (GTK_BOX (vbox), primary_label, FALSE, FALSE, 0);
+
+	vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
+	gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
+
+	select_label = gtk_label_new_with_mnemonic (_("S_elect the images you want to save:"));
+
+	gtk_box_pack_start (GTK_BOX (vbox2), select_label, FALSE, FALSE, 0);
+	gtk_label_set_line_wrap (GTK_LABEL (select_label), TRUE);
+	gtk_label_set_xalign (GTK_LABEL (select_label), 0.0);
+
+	scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
+	gtk_box_pack_start (GTK_BOX (vbox2), scrolledwindow, TRUE, TRUE, 0);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow),
+					     GTK_SHADOW_IN);
+
+	treeview = create_treeview (priv);
+	gtk_container_add (GTK_CONTAINER (scrolledwindow), treeview);
+	gtk_widget_set_size_request (scrolledwindow, 260, 120);
+
+	/* Secondary label */
+	secondary_label = gtk_label_new (_("If you don't save, "
+					   "all your changes will be lost."));
+
+	gtk_box_pack_start (GTK_BOX (vbox2), secondary_label, FALSE, FALSE, 0);
+	gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
+	gtk_label_set_xalign (GTK_LABEL (secondary_label), 0.0);
+	gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
+
+	gtk_label_set_mnemonic_widget (GTK_LABEL (select_label), treeview);
+
+	add_buttons (dlg);
+
+	gtk_widget_show_all (hbox);
+}
+
+static void
+set_unsaved_image (EomCloseConfirmationDialog *dlg,
+		   const GList                *list)
+{
+	EomCloseConfirmationDialogPrivate *priv;
+
+	g_return_if_fail (list != NULL);
+
+	priv = dlg->priv;
+	g_return_if_fail (priv->unsaved_images == NULL);
+
+	priv->unsaved_images = g_list_copy ((GList *)list);
+
+	if (GET_MODE (priv) == SINGLE_IMG_MODE)
+	{
+		build_single_img_dialog (dlg);
+	}
+	else
+	{
+		build_multiple_imgs_dialog (dlg);
+	}
+}
+
+const GList *
+eom_close_confirmation_dialog_get_unsaved_images (EomCloseConfirmationDialog *dlg)
+{
+	g_return_val_if_fail (EOM_IS_CLOSE_CONFIRMATION_DIALOG (dlg), NULL);
+
+	return dlg->priv->unsaved_images;
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/6.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/6.html new file mode 100644 index 0000000..4f46cfd --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/6.html @@ -0,0 +1,598 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
/* Eye Of Mate - Erro Message Area
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <lucasr@gnome.org>
+ *
+ * Based on gedit code (gedit/gedit-message-area.h) by:
+ * 	- Paolo Maggi <paolo@gnome.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eom-error-message-area.h"
+#include "eom-image.h"
+#include "eom-util.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+static void
+set_message_area_text_and_icon (GtkInfoBar   *message_area,
+				const gchar  *icon_name,
+				const gchar  *primary_text,
+				const gchar  *secondary_text)
+{
+	GtkWidget *hbox_content;
+	GtkWidget *image;
+	GtkWidget *vbox;
+	gchar *primary_markup;
+	gchar *secondary_markup;
+	GtkWidget *primary_label;
+	GtkWidget *secondary_label;
+
+	hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
+	gtk_widget_show (hbox_content);
+
+	image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DIALOG);
+	gtk_widget_show (image);
+	gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
+	gtk_widget_set_valign (image, GTK_ALIGN_START);
+
+	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+	gtk_widget_show (vbox);
+	gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
+
+	primary_markup = g_markup_printf_escaped ("<b>%s</b>", primary_text);
+	primary_label = gtk_label_new (primary_markup);
+	g_free (primary_markup);
+
+	gtk_widget_show (primary_label);
+
+	gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
+	gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
+	gtk_label_set_line_wrap (GTK_LABEL (primary_label), FALSE);
+	gtk_label_set_xalign (GTK_LABEL (primary_label), 0.0);
+
+	gtk_widget_set_can_focus (primary_label, TRUE);
+
+	gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
+
+	if (secondary_text != NULL) {
+		secondary_markup = g_markup_printf_escaped ("<small>%s</small>",
+		                                            secondary_text);
+		secondary_label = gtk_label_new (secondary_markup);
+		g_free (secondary_markup);
+
+		gtk_widget_show (secondary_label);
+
+		gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
+
+		gtk_widget_set_can_focus (secondary_label, TRUE);
+
+		gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
+		gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
+		gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
+		gtk_label_set_xalign (GTK_LABEL (secondary_label), 0.0);
+	}
+
+	gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (message_area))), hbox_content, TRUE, TRUE, 0);
+}
+
+static GtkWidget *
+create_error_message_area (const gchar *primary_text,
+			   const gchar *secondary_text,
+			   gboolean     recoverable)
+{
+	GtkWidget *message_area;
+
+	if (recoverable)
+		message_area = gtk_info_bar_new_with_buttons (_("_Retry"),
+							      GTK_RESPONSE_OK,
+							      NULL);
+	else
+		message_area = gtk_info_bar_new ();
+
+	gtk_info_bar_set_message_type (GTK_INFO_BAR (message_area),
+				       GTK_MESSAGE_ERROR);
+
+	set_message_area_text_and_icon (GTK_INFO_BAR (message_area),
+					"dialog-error",
+					primary_text,
+					secondary_text);
+
+	return message_area;
+}
+
+/**
+ * eom_image_load_error_message_area_new:
+ * @caption:
+ * @error:
+ *
+ *
+ *
+ * Returns: (transfer full): a new #GtkInfoArea
+ **/
+GtkWidget *
+eom_image_load_error_message_area_new (const gchar  *caption,
+				       const GError *error)
+{
+	GtkWidget *message_area;
+	gchar *error_message = NULL;
+	gchar *message_details = NULL;
+	gchar *pango_escaped_caption = NULL;
+
+	g_return_val_if_fail (caption != NULL, NULL);
+	g_return_val_if_fail (error != NULL, NULL);
+
+	/* Escape the caption string with respect to pango markup.
+	   This is necessary because otherwise characters like "&" will
+	   be interpreted as the beginning of a pango entity inside
+	   the message area GtkLabel. */
+	pango_escaped_caption = g_markup_escape_text (caption, -1);
+	error_message = g_strdup_printf (_("Could not load image '%s'."),
+					 pango_escaped_caption);
+
+	message_details = eom_util_make_valid_utf8 (error->message);
+
+	message_area = create_error_message_area (error_message,
+						  message_details,
+						  TRUE);
+
+	g_free (pango_escaped_caption);
+	g_free (error_message);
+	g_free (message_details);
+
+	return message_area;
+}
+
+/**
+ * eom_no_images_error_message_area_new:
+ * @file:
+ *
+ *
+ *
+ * Returns: (transfer full): a new #GtkInfoBar
+ **/
+GtkWidget *
+eom_no_images_error_message_area_new (GFile *file)
+{
+	GtkWidget *message_area;
+	gchar *error_message = NULL;
+
+	if (file != NULL) {
+		gchar *uri_str, *unescaped_str, *pango_escaped_str;
+
+		uri_str = g_file_get_uri (file);
+		/* Unescape URI with respect to rules defined in RFC 3986. */
+		unescaped_str = g_uri_unescape_string (uri_str, NULL);
+
+		/* Escape the URI string with respect to pango markup.
+		   This is necessary because the URI string can contain
+		   for example "&" which will otherwise be interpreted
+		   as a pango markup entity when inserted into a GtkLabel. */
+		pango_escaped_str = g_markup_escape_text (unescaped_str, -1);
+		error_message = g_strdup_printf (_("No images found in '%s'."),
+						 pango_escaped_str);
+
+		g_free (pango_escaped_str);
+		g_free (uri_str);
+		g_free (unescaped_str);
+	} else {
+		error_message = g_strdup (_("The given locations contain no images."));
+	}
+
+	message_area = create_error_message_area (error_message,
+						  NULL,
+						  FALSE);
+
+	g_free (error_message);
+
+	return message_area;
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/7.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/7.html new file mode 100644 index 0000000..6a2c256 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/7.html @@ -0,0 +1,890 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
/* Eye Of Mate - EXIF Utilities
+ *
+ * Copyright (C) 2006-2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <lucasr@gnome.org>
+ * Author: Claudio Saavedra <csaavedra@alumnos.utalca.cl>
+ * Author: Felix Riemann <felix@hsgheli.de>
+ *
+ * Based on code by:
+ *	- Jens Finke <jens@gnome.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STRPTIME
+#define _XOPEN_SOURCE
+#define _XOPEN_SOURCE_EXTENDED 1
+#endif
+#include <time.h>
+
+#include "eom-exif-util.h"
+#include "eom-util.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#define DATE_BUF_SIZE 200
+
+/* gboolean <-> gpointer conversion macros taken from gedit */
+#ifndef GBOOLEAN_TO_POINTER
+#define GBOOLEAN_TO_POINTER(i) (GINT_TO_POINTER ((i) ? 2 : 1))
+#endif
+#ifndef GPOINTER_TO_BOOLEAN
+#define GPOINTER_TO_BOOLEAN(i) ((gboolean) ((GPOINTER_TO_INT (i) == 2) ? TRUE : FALSE))
+#endif
+
+typedef ExifData EomExifData;
+
+/* Define EomExifData type */
+G_DEFINE_BOXED_TYPE(EomExifData, eom_exif_data, eom_exif_data_copy, eom_exif_data_free)
+
+#ifdef HAVE_STRPTIME
+static gpointer
+_check_strptime_updates_wday (gpointer data)
+{
+	struct tm tm;
+
+	memset (&tm, '\0', sizeof (tm));
+	strptime ("2008:12:24 20:30:45", "%Y:%m:%d %T", &tm);
+	/* Check if tm.tm_wday is set to Wednesday (3) now */
+	return GBOOLEAN_TO_POINTER (tm.tm_wday == 3);
+}
+#endif
+
+/**
+ * _calculate_wday_yday:
+ * @tm: A struct tm that should be updated.
+ *
+ * Ensure tm_wday and tm_yday are set correctly in a struct tm.
+ * The other date (dmy) values must have been set already.
+ **/
+static void
+_calculate_wday_yday (struct tm *tm)
+{
+	GDate *exif_date;
+	struct tm tmp_tm;
+
+	exif_date = g_date_new_dmy (tm->tm_mday,
+				    tm->tm_mon+1,
+				    tm->tm_year+1900);
+
+	g_return_if_fail (exif_date != NULL && g_date_valid (exif_date));
+
+	// Use this to get GLib <-> libc corrected values
+	g_date_to_struct_tm (exif_date, &tmp_tm);
+	g_date_free (exif_date);
+
+	tm->tm_wday = tmp_tm.tm_wday;
+	tm->tm_yday = tmp_tm.tm_yday;
+}
+
+/* Older GCCs don't support pragma diagnostic inside functions.
+ * Put these here to avoid problems with the strftime format strings
+ * without breaking the build for these older GCCs */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+
+#ifdef HAVE_STRPTIME
+static gchar *
+eom_exif_util_format_date_with_strptime (const gchar *date, const gchar* format)
+{
+	static GOnce strptime_updates_wday = G_ONCE_INIT;
+	gchar *new_date = NULL;
+	gchar tmp_date[DATE_BUF_SIZE];
+	gchar *p;
+	gsize dlen;
+	struct tm tm;
+
+	memset (&tm, '\0', sizeof (tm));
+	p = strptime (date, "%Y:%m:%d %T", &tm);
+
+	if (p == date + strlen (date)) {
+		g_once (&strptime_updates_wday,
+			_check_strptime_updates_wday,
+			NULL);
+
+		// Ensure tm.tm_wday and tm.tm_yday are set
+		if (!GPOINTER_TO_BOOLEAN (strptime_updates_wday.retval))
+			_calculate_wday_yday (&tm);
+
+		/* A strftime-formatted string, to display the date the image was taken.  */
+		dlen = strftime (tmp_date, DATE_BUF_SIZE * sizeof(gchar), format, &tm);
+		new_date = g_strndup (tmp_date, dlen);
+	}
+
+	return new_date;
+}
+#else
+static gchar *
+eom_exif_util_format_date_by_hand (const gchar *date, const gchar* format)
+{
+	int year, month, day, hour, minutes, seconds;
+	int result;
+	gchar *new_date = NULL;
+
+	result = sscanf (date, "%d:%d:%d %d:%d:%d",
+			 &year, &month, &day, &hour, &minutes, &seconds);
+
+	if (result < 3 || !g_date_valid_dmy (day, month, year)) {
+		return NULL;
+	} else {
+		gchar tmp_date[DATE_BUF_SIZE];
+		gsize dlen;
+		struct tm tm;
+
+		memset (&tm, '\0', sizeof (tm));
+		tm.tm_mday = day;
+		tm.tm_mon = month-1;
+		tm.tm_year = year-1900;
+		// Calculate tm.tm_wday
+		_calculate_wday_yday (&tm);
+
+		tm.tm_sec = result < 6 ? 0 : seconds;
+		tm.tm_min = result < 5 ? 0 : minutes;
+		tm.tm_hour = result < 4 ? 0 : hour;
+		dlen = strftime (tmp_date, DATE_BUF_SIZE * sizeof(gchar), format, &tm);
+
+		if (dlen == 0)
+			return NULL;
+		else
+			new_date = g_strndup (tmp_date, dlen);
+	}
+	return new_date;
+}
+#endif /* HAVE_STRPTIME */
+
+#pragma GCC diagnostic pop
+
+/**
+ * eom_exif_util_format_date:
+ * @date: a date string following Exif specifications
+ *
+ * Takes a date string formatted after Exif specifications and generates a
+ * more readable, possibly localized, string out of it.
+ *
+ * Returns: a newly allocated date string formatted according to the
+ * current locale.
+ */
+gchar *
+eom_exif_util_format_date (const gchar *date)
+{
+	gchar *new_date;
+#ifdef HAVE_STRPTIME
+	/* A strftime-formatted string, to display the date the image was taken.  */
+	new_date = eom_exif_util_format_date_with_strptime (date, _("%a, %d %B %Y  %X"));
+#else
+	new_date = eom_exif_util_format_date_by_hand (date, _("%a, %d %B %Y  %X"));
+#endif /* HAVE_STRPTIME */
+	return new_date;
+}
+
+void
+eom_exif_util_set_label_text (GtkLabel *label,
+			      EomExifData *exif_data,
+			      gint tag_id)
+{
+	gchar exif_buffer[512];
+	const gchar *buf_ptr;
+	gchar *label_text = NULL;
+
+	g_return_if_fail (GTK_IS_LABEL (label));
+
+	if (exif_data) {
+		buf_ptr = eom_exif_data_get_value (exif_data, tag_id,
+						   exif_buffer, 512);
+
+		if (tag_id == EXIF_TAG_DATE_TIME_ORIGINAL && buf_ptr)
+			label_text = eom_exif_util_format_date (buf_ptr);
+		else
+			label_text = eom_util_make_valid_utf8 (buf_ptr);
+	}
+
+	gtk_label_set_text (label, label_text);
+	g_free (label_text);
+}
+
+void
+eom_exif_util_format_datetime_label (GtkLabel *label, EomExifData *exif_data,
+                                     gint tag_id, const gchar *format)
+{
+	gchar exif_buffer[512];
+	const gchar *buf_ptr;
+	gchar *label_text = NULL;
+
+	g_return_if_fail (GTK_IS_LABEL (label));
+	g_warn_if_fail (tag_id == EXIF_TAG_DATE_TIME_ORIGINAL);
+
+	if (exif_data) {
+	    buf_ptr = eom_exif_data_get_value (exif_data, tag_id,
+	                                       exif_buffer, 512);
+
+	    if (tag_id == EXIF_TAG_DATE_TIME_ORIGINAL && buf_ptr)
+#ifdef HAVE_STRPTIME
+	        label_text = eom_exif_util_format_date_with_strptime (buf_ptr, format);
+#else
+	        label_text = eom_exif_util_format_date_by_hand (buf_ptr, format);
+#endif /* HAVE_STRPTIME */
+	}
+
+	gtk_label_set_text (label, label_text);
+	g_free (label_text);
+}
+
+void
+eom_exif_util_set_focal_length_label_text (GtkLabel *label,
+					   EomExifData *exif_data)
+{
+	ExifEntry *entry = NULL, *entry35mm = NULL;
+	ExifByteOrder byte_order;
+	gfloat f_val = 0.0;
+	gchar *fl_text = NULL,*fl35_text = NULL;
+
+	/* If no ExifData is supplied the label will be
+	 * cleared later as fl35_text is NULL. */
+	if (exif_data != NULL) {
+		entry = exif_data_get_entry (exif_data, EXIF_TAG_FOCAL_LENGTH);
+		entry35mm = exif_data_get_entry (exif_data,
+					    EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM);
+		byte_order = exif_data_get_byte_order (exif_data);
+	}
+
+	if (entry && G_LIKELY (entry->format == EXIF_FORMAT_RATIONAL)) {
+		ExifRational value;
+
+		/* Decode value by hand as libexif is not necessarily returning
+		 * it in the format we want it to be.
+		 */
+		value = exif_get_rational (entry->data, byte_order);
+		/* Guard against div by zero */
+		if (G_LIKELY(value.denominator != 0))
+			f_val = (gfloat)value.numerator/
+				(gfloat)value.denominator;
+
+		/* TRANSLATORS: This is the actual focal length used when
+		   the image was taken.*/
+		fl_text = g_strdup_printf (_("%.1f (lens)"), f_val);
+
+	}
+	if (entry35mm && G_LIKELY (entry35mm->format == EXIF_FORMAT_SHORT)) {
+		ExifShort s_val;
+
+		s_val = exif_get_short (entry35mm->data, byte_order);
+
+		/* Print as float to get a similar look as above. */
+		/* TRANSLATORS: This is the equivalent focal length assuming
+		   a 35mm film camera. */
+		fl35_text = g_strdup_printf(_("%.1f (35mm film)"),(float)s_val);
+	}
+
+	if (fl_text) {
+		if (fl35_text) {
+			gchar *merged_txt;
+
+			merged_txt = g_strconcat (fl35_text,", ", fl_text, NULL);
+			gtk_label_set_text (label, merged_txt);
+			g_free (merged_txt);
+		} else {
+			gtk_label_set_text (label, fl_text);
+		}
+	} else {
+		/* This will also clear the label if no ExifData was supplied */
+		gtk_label_set_text (label, fl35_text);
+	}
+
+	g_free (fl35_text);
+	g_free (fl_text);
+}
+
+/**
+ * eom_exif_data_get_value:
+ * @exif_data: pointer to an <structname>ExifData</structname> struct
+ * @tag_id: the requested tag's id. See <filename>exif-tag.h</filename>
+ * from the libexif package for possible values (e.g. %EXIF_TAG_EXPOSURE_MODE).
+ * @buffer: a pre-allocated output buffer
+ * @buf_size: size of @buffer
+ *
+ * Convenience function to extract a string representation of an Exif tag
+ * directly from an <structname>ExifData</structname> struct. The string is
+ * written into @buffer as far as @buf_size permits.
+ *
+ * Returns: a pointer to @buffer.
+ */
+const gchar *
+eom_exif_data_get_value (EomExifData *exif_data, gint tag_id, gchar *buffer, guint buf_size)
+{
+	ExifEntry *exif_entry;
+	const gchar *exif_value;
+
+        exif_entry = exif_data_get_entry (exif_data, tag_id);
+
+	buffer[0] = 0;
+
+	exif_value = exif_entry_get_value (exif_entry, buffer, buf_size);
+
+	return exif_value;
+}
+
+EomExifData *
+eom_exif_data_copy (EomExifData *data)
+{
+	exif_data_ref (data);
+
+	return data;
+}
+
+void
+eom_exif_data_free (EomExifData *data)
+{
+	exif_data_unref (data);
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/8.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/8.html new file mode 100644 index 0000000..e517354 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/8.html @@ -0,0 +1,1272 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
/*
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "eom-file-chooser.h"
+#include "eom-config-keys.h"
+#include "eom-pixbuf-util.h"
+
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+/* We must define MATE_DESKTOP_USE_UNSTABLE_API to be able
+   to use MateDesktopThumbnail */
+#ifndef MATE_DESKTOP_USE_UNSTABLE_API
+#define MATE_DESKTOP_USE_UNSTABLE_API
+#endif
+#include <libmate-desktop/mate-desktop-thumbnail.h>
+
+static char *last_dir[] = { NULL, NULL, NULL, NULL };
+
+#define FILE_FORMAT_KEY "file-format"
+
+struct _EomFileChooserPrivate
+{
+	MateDesktopThumbnailFactory *thumb_factory;
+
+	GtkWidget *image;
+	GtkWidget *size_label;
+	GtkWidget *dim_label;
+	GtkWidget *creator_label;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (EomFileChooser, eom_file_chooser, GTK_TYPE_FILE_CHOOSER_DIALOG)
+
+static void
+eom_file_chooser_finalize (GObject *object)
+{
+	EomFileChooserPrivate *priv;
+
+	priv = EOM_FILE_CHOOSER (object)->priv;
+
+	if (priv->thumb_factory != NULL)
+		g_object_unref (priv->thumb_factory);
+
+	(* G_OBJECT_CLASS (eom_file_chooser_parent_class)->finalize) (object);
+}
+
+static void
+eom_file_chooser_class_init (EomFileChooserClass *klass)
+{
+	GObjectClass *object_class = (GObjectClass *) klass;
+
+	object_class->finalize = eom_file_chooser_finalize;
+}
+
+static void
+eom_file_chooser_init (EomFileChooser *chooser)
+{
+	chooser->priv = eom_file_chooser_get_instance_private (chooser);
+}
+
+static void
+response_cb (GtkDialog *dlg, gint id, gpointer data)
+{
+	char *dir;
+	GtkFileChooserAction action;
+
+	if (id == GTK_RESPONSE_OK) {
+		dir = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dlg));
+		action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dlg));
+
+		if (last_dir [action] != NULL)
+			g_free (last_dir [action]);
+
+		last_dir [action] = dir;
+	}
+}
+
+static void
+save_response_cb (GtkDialog *dlg, gint id, gpointer data)
+{
+	GFile *file;
+	GdkPixbufFormat *format;
+
+	if (id != GTK_RESPONSE_OK)
+		return;
+
+	file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dlg));
+	format = eom_pixbuf_get_format (file);
+	g_object_unref (file);
+
+	if (!format || !gdk_pixbuf_format_is_writable (format)) {
+		GtkWidget *msg_dialog;
+
+		msg_dialog = gtk_message_dialog_new (
+						     GTK_WINDOW (dlg),
+						     GTK_DIALOG_MODAL,
+						     GTK_MESSAGE_ERROR,
+						     GTK_BUTTONS_OK,
+						     _("File format is unknown or unsupported"));
+
+		gtk_message_dialog_format_secondary_text (
+						GTK_MESSAGE_DIALOG (msg_dialog),
+						"%s\n%s",
+		 				_("Eye of MATE could not determine a supported writable file format based on the filename."),
+		  				_("Please try a different file extension like .png or .jpg."));
+
+		gtk_dialog_run (GTK_DIALOG (msg_dialog));
+		gtk_widget_destroy (msg_dialog);
+
+		g_signal_stop_emission_by_name (dlg, "response");
+	} else {
+		response_cb (dlg, id, data);
+	}
+}
+
+static void
+eom_file_chooser_add_filter (EomFileChooser *chooser)
+{
+	GSList *it;
+	GSList *formats;
+ 	GtkFileFilter *all_file_filter;
+	GtkFileFilter *all_img_filter;
+	GtkFileFilter *filter;
+	GSList *filters = NULL;
+	gchar **mime_types, **pattern, *tmp;
+	int i;
+	GtkFileChooserAction action;
+
+	action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (chooser));
+
+	if (action != GTK_FILE_CHOOSER_ACTION_SAVE && action != GTK_FILE_CHOOSER_ACTION_OPEN) {
+		return;
+	}
+
+	/* All Files Filter */
+	all_file_filter = gtk_file_filter_new ();
+	gtk_file_filter_set_name (all_file_filter, _("All Files"));
+	gtk_file_filter_add_pattern (all_file_filter, "*");
+
+	/* All Image Filter */
+	all_img_filter = gtk_file_filter_new ();
+	gtk_file_filter_set_name (all_img_filter, _("All Images"));
+
+	if (action == GTK_FILE_CHOOSER_ACTION_SAVE) {
+		formats = eom_pixbuf_get_savable_formats ();
+	}
+	else {
+		formats = gdk_pixbuf_get_formats ();
+	}
+
+	/* Image filters */
+	for (it = formats; it != NULL; it = it->next) {
+		char *filter_name;
+		char *description, *extension;
+		GdkPixbufFormat *format;
+		filter = gtk_file_filter_new ();
+
+		format = (GdkPixbufFormat*) it->data;
+		description = gdk_pixbuf_format_get_description (format);
+		extension = gdk_pixbuf_format_get_name (format);
+
+		/* Filter name: First description then file extension, eg. "The PNG-Format (*.png)".*/
+		filter_name = g_strdup_printf (_("%s (*.%s)"), description, extension);
+		g_free (description);
+		g_free (extension);
+
+		gtk_file_filter_set_name (filter, filter_name);
+		g_free (filter_name);
+
+		mime_types = gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) it->data);
+		for (i = 0; mime_types[i] != NULL; i++) {
+			gtk_file_filter_add_mime_type (filter, mime_types[i]);
+			gtk_file_filter_add_mime_type (all_img_filter, mime_types[i]);
+		}
+		g_strfreev (mime_types);
+
+		pattern = gdk_pixbuf_format_get_extensions ((GdkPixbufFormat *) it->data);
+		for (i = 0; pattern[i] != NULL; i++) {
+			tmp = g_strconcat ("*.", pattern[i], NULL);
+			gtk_file_filter_add_pattern (filter, tmp);
+			gtk_file_filter_add_pattern (all_img_filter, tmp);
+			g_free (tmp);
+		}
+		g_strfreev (pattern);
+
+		/* attach GdkPixbufFormat to filter, see also
+		 * eom_file_chooser_get_format. */
+		g_object_set_data (G_OBJECT (filter),
+				   FILE_FORMAT_KEY,
+				   format);
+
+		filters = g_slist_prepend (filters, filter);
+	}
+	g_slist_free (formats);
+
+	/* Add filter to filechooser */
+	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), all_file_filter);
+	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), all_img_filter);
+	gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser), all_img_filter);
+
+	for (it = filters; it != NULL; it = it->next) {
+		gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), GTK_FILE_FILTER (it->data));
+	}
+	g_slist_free (filters);
+}
+
+static void
+set_preview_label (GtkWidget *label, const char *str)
+{
+	if (str == NULL) {
+		gtk_widget_hide (GTK_WIDGET (label));
+	}
+	else {
+		gtk_label_set_text (GTK_LABEL (label), str);
+		gtk_widget_show (GTK_WIDGET (label));
+	}
+}
+
+/* Sets the pixbuf as preview thumbnail and tries to read and display
+ * further information according to the thumbnail spec.
+ */
+static void
+set_preview_pixbuf (EomFileChooser *chooser, GdkPixbuf *pixbuf, goffset size)
+{
+	EomFileChooserPrivate *priv;
+	int bytes;
+	int pixels;
+	const char *bytes_str;
+	const char *width;
+	const char *height;
+	const char *creator = NULL;
+	char *size_str    = NULL;
+	char *dim_str     = NULL;
+
+	g_return_if_fail (EOM_IS_FILE_CHOOSER (chooser));
+
+	priv = chooser->priv;
+
+	gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), pixbuf);
+
+	if (pixbuf != NULL) {
+		/* try to read file size */
+		bytes_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Size");
+		if (bytes_str != NULL) {
+			bytes = atoi (bytes_str);
+			size_str = g_format_size (bytes);
+		}
+		else {
+			size_str = g_format_size (size);
+		}
+
+		/* try to read image dimensions */
+		width  = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Width");
+		height = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Height");
+
+		if ((width != NULL) && (height != NULL)) {
+			pixels = atoi (height);
+			/* Pixel size of image: width x height in pixel */
+			dim_str = g_strdup_printf ("%s x %s %s", width, height, ngettext ("pixel", "pixels", pixels));
+		}
+
+#if 0
+		/* Not sure, if this is really useful, therefore its commented out for now. */
+
+		/* try to read creator of the thumbnail */
+		creator = gdk_pixbuf_get_option (pixbuf, "tEXt::Software");
+
+		/* stupid workaround to display nicer string if the
+		 * thumbnail is created through the mate libraries.
+		 */
+		if (g_ascii_strcasecmp (creator, "Mate::ThumbnailFactory") == 0) {
+			creator = "MATE Libs";
+		}
+#endif
+	}
+
+	set_preview_label (priv->size_label, size_str);
+	set_preview_label (priv->dim_label, dim_str);
+	set_preview_label (priv->creator_label, creator);
+
+	if (size_str != NULL) {
+		g_free (size_str);
+	}
+
+	if (dim_str != NULL) {
+		g_free (dim_str);
+	}
+}
+
+static void
+update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
+{
+	EomFileChooserPrivate *priv;
+	char *uri;
+	char *thumb_path = NULL;
+	GFile *file;
+	GFileInfo *file_info;
+	GdkPixbuf *pixbuf = NULL;
+	gboolean have_preview = FALSE;
+
+	priv = EOM_FILE_CHOOSER (file_chooser)->priv;
+
+	uri = gtk_file_chooser_get_preview_uri (file_chooser);
+	if (uri == NULL) {
+		gtk_file_chooser_set_preview_widget_active (file_chooser, FALSE);
+		return;
+	}
+
+	file = g_file_new_for_uri (uri);
+	file_info = g_file_query_info (file,
+				       G_FILE_ATTRIBUTE_TIME_MODIFIED ","
+				       G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+				       G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+				       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+				       0, NULL, NULL);
+	g_object_unref (file);
+
+	if ((file_info != NULL) && (priv->thumb_factory != NULL)
+	    && g_file_info_get_file_type (file_info) != G_FILE_TYPE_SPECIAL) {
+		guint64 mtime;
+
+		mtime = g_file_info_get_attribute_uint64 (file_info,
+							  G_FILE_ATTRIBUTE_TIME_MODIFIED);
+		thumb_path = mate_desktop_thumbnail_factory_lookup (priv->thumb_factory, uri, mtime);
+
+		if (thumb_path != NULL && g_file_test (thumb_path, G_FILE_TEST_EXISTS)) {
+			/* try to load and display preview thumbnail */
+			pixbuf = gdk_pixbuf_new_from_file (thumb_path, NULL);
+		} else if (g_file_info_get_size (file_info) <= 100000) {
+			/* read files smaller than 100kb directly */
+
+			gchar *mime_type = g_content_type_get_mime_type (
+						g_file_info_get_content_type (file_info));
+
+
+			if (G_LIKELY (mime_type)) {
+				gboolean can_thumbnail, has_failed;
+
+				can_thumbnail = mate_desktop_thumbnail_factory_can_thumbnail (
+							priv->thumb_factory,
+							uri, mime_type, mtime);
+				has_failed = mate_desktop_thumbnail_factory_has_valid_failed_thumbnail (
+							priv->thumb_factory,
+							uri, mtime);
+
+				if (G_LIKELY (can_thumbnail && !has_failed))
+					pixbuf = mate_desktop_thumbnail_factory_generate_thumbnail (
+							priv->thumb_factory, uri, mime_type);
+
+				g_free (mime_type);
+			}
+		}
+
+		if (pixbuf != NULL) {<--- Assuming that condition 'pixbuf!=NULL' is not redundant
+			have_preview = TRUE;
+
+			set_preview_pixbuf (EOM_FILE_CHOOSER (file_chooser), pixbuf,
+					    g_file_info_get_size (file_info));
+
+			if (pixbuf != NULL) {<--- Condition 'pixbuf!=NULL' is always true
+				g_object_unref (pixbuf);
+			}
+		}
+	}
+
+	if (thumb_path != NULL) {
+		g_free (thumb_path);
+	}
+
+	g_free (uri);
+	g_object_unref (file_info);
+
+	gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
+}
+
+static void
+eom_file_chooser_add_preview (GtkWidget *widget)
+{
+	EomFileChooserPrivate *priv;
+	GtkWidget *vbox;
+
+	priv = EOM_FILE_CHOOSER (widget)->priv;
+
+	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+
+	priv->image      = gtk_image_new ();
+	/* 128x128 is maximum size of thumbnails */
+	gtk_widget_set_size_request (priv->image, 128,128);
+
+	priv->dim_label  = gtk_label_new (NULL);
+	priv->size_label = gtk_label_new (NULL);
+	priv->creator_label = gtk_label_new (NULL);
+
+	gtk_box_pack_start (GTK_BOX (vbox), priv->image, FALSE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (vbox), priv->dim_label, FALSE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (vbox), priv->size_label, FALSE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (vbox), priv->creator_label, FALSE, TRUE, 0);
+
+	gtk_widget_show_all (vbox);
+
+	gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (widget), vbox);
+	gtk_file_chooser_set_preview_widget_active (GTK_FILE_CHOOSER (widget), FALSE);
+
+	priv->thumb_factory = mate_desktop_thumbnail_factory_new (MATE_DESKTOP_THUMBNAIL_SIZE_NORMAL);
+
+	g_signal_connect (widget, "update-preview",
+			  G_CALLBACK (update_preview_cb), NULL);
+}
+
+GtkWidget *
+eom_file_chooser_new (GtkFileChooserAction action)
+{
+	GtkWidget *chooser;
+	gchar *title = NULL;
+
+	chooser = g_object_new (EOM_TYPE_FILE_CHOOSER,
+				"action", action,
+				"select-multiple", (action == GTK_FILE_CHOOSER_ACTION_OPEN),
+				"local-only", FALSE,
+				NULL);
+
+	switch (action) {
+	case GTK_FILE_CHOOSER_ACTION_OPEN:
+		gtk_dialog_add_buttons (GTK_DIALOG (chooser),
+					"gtk-cancel", GTK_RESPONSE_CANCEL,
+					"gtk-open", GTK_RESPONSE_OK,
+					NULL);
+		title = _("Open Image");
+		break;
+
+	case GTK_FILE_CHOOSER_ACTION_SAVE:
+		gtk_dialog_add_buttons (GTK_DIALOG (chooser),
+					"gtk-cancel", GTK_RESPONSE_CANCEL,
+					"gtk-save", GTK_RESPONSE_OK,
+					NULL);
+		title = _("Save Image");
+		break;
+
+	case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
+		gtk_dialog_add_buttons (GTK_DIALOG (chooser),
+					"gtk-cancel", GTK_RESPONSE_CANCEL,
+					"gtk-open", GTK_RESPONSE_OK,
+					NULL);
+		title = _("Open Folder");
+		break;
+
+	default:
+		g_assert_not_reached ();
+	}
+
+	if (action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) {
+		eom_file_chooser_add_filter (EOM_FILE_CHOOSER (chooser));
+		eom_file_chooser_add_preview (chooser);
+	}
+
+	if (last_dir[action] != NULL) {
+		gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), last_dir [action]);
+	}
+
+	g_signal_connect (chooser, "response",
+			  G_CALLBACK ((action == GTK_FILE_CHOOSER_ACTION_SAVE) ?
+				      save_response_cb : response_cb),
+			  NULL);
+
+ 	gtk_window_set_title (GTK_WINDOW (chooser), title);
+	gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
+
+	gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (chooser), TRUE);
+
+	return chooser;
+}
+
+GdkPixbufFormat *
+eom_file_chooser_get_format (EomFileChooser *chooser)
+{
+	GtkFileFilter *filter;
+	GdkPixbufFormat* format;
+
+	g_return_val_if_fail (EOM_IS_FILE_CHOOSER (chooser), NULL);
+
+	filter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (chooser));
+	if (filter == NULL)
+		return NULL;
+
+	format = g_object_get_data (G_OBJECT (filter), FILE_FORMAT_KEY);
+
+	return format;
+}
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/9.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/9.html new file mode 100644 index 0000000..67d1bae --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/9.html @@ -0,0 +1,1226 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
/* This code is based on the jpeg saving code from gdk-pixbuf. Full copyright
+ * notice is given in the following:
+ */
+/* GdkPixbuf library - JPEG image loader
+ *
+ * Copyright (C) 1999 Michael Zucchi
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Progressive loading code Copyright (C) 1999 Red Hat, Inc.
+ *
+ * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Michael Fulbright <drmike@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eom-image-jpeg.h"
+#include "eom-image-private.h"
+
+#if HAVE_JPEG
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+#include <jpeglib.h>
+#include <jerror.h>
+#include "transupp.h"
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <glib/gi18n.h>
+#if HAVE_EXIF
+#include <libexif/exif-data.h>
+#endif
+
+#ifdef G_OS_WIN32
+#define sigjmp_buf jmp_buf
+#define sigsetjmp(env, savesigs) setjmp (env)
+#define siglongjmp longjmp
+#endif
+
+typedef enum {
+	EOM_SAVE_NONE,
+	EOM_SAVE_JPEG_AS_JPEG,
+	EOM_SAVE_ANY_AS_JPEG
+} EomJpegSaveMethod;
+
+/* error handler data */
+struct error_handler_data {
+	struct jpeg_error_mgr pub;
+	sigjmp_buf setjmp_buffer;
+        GError **error;
+	char *filename;
+};
+
+
+static void
+fatal_error_handler (j_common_ptr cinfo)
+{
+	struct error_handler_data *errmgr;
+        char buffer[JMSG_LENGTH_MAX];
+
+	errmgr = (struct error_handler_data *) cinfo->err;
+
+        /* Create the message */
+        (* cinfo->err->format_message) (cinfo, buffer);
+
+        /* broken check for *error == NULL for robustness against
+         * crappy JPEG library
+         */
+        if (errmgr->error && *errmgr->error == NULL) {
+                gchar *str = g_path_get_basename (errmgr->filename);
+                g_set_error (errmgr->error,
+			     0,
+			     0,
+			     "Error interpreting JPEG image file: %s\n\n%s",
+			     str, buffer);
+                g_free (str);
+        }
+
+	siglongjmp (errmgr->setjmp_buffer, 1);
+
+        g_assert_not_reached ();
+}
+
+
+static void
+output_message_handler (j_common_ptr cinfo)
+{
+	/* This method keeps libjpeg from dumping crap to stderr */
+	/* do nothing */
+}
+
+static void
+init_transform_info (EomImage *image, jpeg_transform_info *info)
+{
+	EomImagePrivate *priv;
+	EomTransform *composition = NULL;
+	EomTransformType transformation;
+	JXFORM_CODE trans_code = JXFORM_NONE;
+
+	g_return_if_fail (EOM_IS_IMAGE (image));
+
+	memset (info, 0x0, sizeof (jpeg_transform_info));
+
+	priv = image->priv;
+
+	if (priv->trans != NULL && priv->trans_autorotate != NULL) {
+		composition = eom_transform_compose (priv->trans,
+						     priv->trans_autorotate);
+	} else if (priv->trans != NULL) {
+		composition = g_object_ref (priv->trans);
+	} else if (priv->trans_autorotate != NULL) {
+		composition = g_object_ref (priv->trans_autorotate);
+	}
+
+	if (composition != NULL) {
+		transformation = eom_transform_get_transform_type (composition);
+
+		switch (transformation) {
+		case EOM_TRANSFORM_ROT_90:
+			trans_code = JXFORM_ROT_90;
+			break;
+		case EOM_TRANSFORM_ROT_270:
+			trans_code = JXFORM_ROT_270;
+			break;
+		case EOM_TRANSFORM_ROT_180:
+			trans_code = JXFORM_ROT_180;
+			break;
+		case EOM_TRANSFORM_FLIP_HORIZONTAL:
+			trans_code = JXFORM_FLIP_H;
+			break;
+		case EOM_TRANSFORM_FLIP_VERTICAL:
+			trans_code = JXFORM_FLIP_V;
+			break;
+		case EOM_TRANSFORM_TRANSPOSE:
+			trans_code = JXFORM_TRANSPOSE;
+			break;
+		case EOM_TRANSFORM_TRANSVERSE:
+			trans_code = JXFORM_TRANSVERSE;
+			break;
+		default:
+			g_warning("EomTransformType not supported!");
+			/* Fallthrough intended here. */
+		case EOM_TRANSFORM_NONE:
+			trans_code = JXFORM_NONE;
+			break;
+		}
+	}
+
+	info->transform = trans_code;
+	info->trim      = FALSE;
+#if JPEG_LIB_VERSION >= 80
+	info->crop = FALSE;
+#endif
+	info->force_grayscale = FALSE;
+
+	g_object_unref (composition);
+}
+
+static gboolean
+_save_jpeg_as_jpeg (EomImage *image, const char *file, EomImageSaveInfo *source,
+		    EomImageSaveInfo *target, GError **error)
+{
+	struct jpeg_decompress_struct  srcinfo;
+	struct jpeg_compress_struct    dstinfo;
+	struct error_handler_data      jsrcerr, jdsterr;
+	jpeg_transform_info            transformoption;
+	jvirt_barray_ptr              *src_coef_arrays;
+	jvirt_barray_ptr              *dst_coef_arrays;
+	FILE                          *output_file;
+	FILE                          *input_file;
+	EomImagePrivate               *priv;
+	gchar                          *infile_uri;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (image), FALSE);
+	g_return_val_if_fail (EOM_IMAGE (image)->priv->file != NULL, FALSE);
+
+	priv = image->priv;
+
+	init_transform_info (image, &transformoption);
+
+	/* Initialize the JPEG decompression object with default error
+	 * handling. */
+	jsrcerr.filename = g_file_get_path (priv->file);
+	srcinfo.err = jpeg_std_error (&(jsrcerr.pub));
+	jsrcerr.pub.error_exit = fatal_error_handler;
+	jsrcerr.pub.output_message = output_message_handler;
+	jsrcerr.error = error;<--- Variable 'jsrcerr.error' is assigned a value that is never used.
+
+	jpeg_create_decompress (&srcinfo);
+
+	/* Initialize the JPEG compression object with default error
+	 * handling. */
+	jdsterr.filename = (char *) file;<--- Variable 'jdsterr.filename' is assigned a value that is never used.
+	dstinfo.err = jpeg_std_error (&(jdsterr.pub));
+	jdsterr.pub.error_exit = fatal_error_handler;
+	jdsterr.pub.output_message = output_message_handler;
+	jdsterr.error = error;<--- Variable 'jdsterr.error' is assigned a value that is never used.
+
+	jpeg_create_compress (&dstinfo);
+
+	dstinfo.err->trace_level = 0;
+	dstinfo.arith_code = FALSE;
+	dstinfo.optimize_coding = FALSE;
+
+	jsrcerr.pub.trace_level = jdsterr.pub.trace_level;
+	srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;
+
+	/* Open the output file. */
+	/* FIXME: Make this a GIO aware input manager */
+	infile_uri = g_file_get_path (priv->file);
+	input_file = fopen (infile_uri, "rb");
+	if (input_file == NULL) {
+		g_warning ("Input file not openable: %s\n", infile_uri);
+		g_free (jsrcerr.filename);
+		g_free (infile_uri);
+		return FALSE;
+	}
+	g_free (infile_uri);
+
+	output_file = fopen (file, "wb");
+	if (output_file == NULL) {
+		g_warning ("Output file not openable: %s\n", file);
+		fclose (input_file);
+		g_free (jsrcerr.filename);
+		return FALSE;
+	}
+
+	if (sigsetjmp (jsrcerr.setjmp_buffer, 1)) {
+		fclose (output_file);
+		fclose (input_file);
+		jpeg_destroy_compress (&dstinfo);
+		jpeg_destroy_decompress (&srcinfo);
+		g_free (jsrcerr.filename);
+		return FALSE;
+	}
+
+	if (sigsetjmp (jdsterr.setjmp_buffer, 1)) {
+		fclose (output_file);
+		fclose (input_file);
+		jpeg_destroy_compress (&dstinfo);
+		jpeg_destroy_decompress (&srcinfo);
+		g_free (jsrcerr.filename);
+		return FALSE;
+	}
+
+	/* Specify data source for decompression */
+	jpeg_stdio_src (&srcinfo, input_file);
+
+	/* Enable saving of extra markers that we want to copy */
+	jcopy_markers_setup (&srcinfo, JCOPYOPT_DEFAULT);
+
+	/* Read file header */
+	(void) jpeg_read_header (&srcinfo, TRUE);
+
+	/* Any space needed by a transform option must be requested before
+	 * jpeg_read_coefficients so that memory allocation will be done right.
+	 */
+	jtransform_request_workspace (&srcinfo, &transformoption);
+
+	/* Read source file as DCT coefficients */
+	src_coef_arrays = jpeg_read_coefficients (&srcinfo);
+
+	/* Initialize destination compression parameters from source values */
+	jpeg_copy_critical_parameters (&srcinfo, &dstinfo);
+
+	/* Adjust destination parameters if required by transform options;
+	 * also find out which set of coefficient arrays will hold the output.
+	 */
+	dst_coef_arrays = jtransform_adjust_parameters (&srcinfo,
+							&dstinfo,
+							src_coef_arrays,
+							&transformoption);
+
+	/* Specify data destination for compression */
+	jpeg_stdio_dest (&dstinfo, output_file);
+
+	/* Start compressor (note no image data is actually written here) */
+	jpeg_write_coefficients (&dstinfo, dst_coef_arrays);
+
+	/* handle EXIF/IPTC data explicitly */
+#if HAVE_EXIF
+	/* exif_chunk and exif are mutally exclusvie, this is what we assure here */
+	g_assert (priv->exif_chunk == NULL);
+	if (priv->exif != NULL)
+	{
+		unsigned char *exif_buf;
+		unsigned int   exif_buf_len;
+
+		exif_data_save_data (priv->exif, &exif_buf, &exif_buf_len);
+		jpeg_write_marker (&dstinfo, JPEG_APP0+1, exif_buf, exif_buf_len);
+		g_free (exif_buf);
+	}
+#else
+	if (priv->exif_chunk != NULL) {
+		jpeg_write_marker (&dstinfo, JPEG_APP0+1, priv->exif_chunk, priv->exif_chunk_len);
+	}
+#endif
+	/* FIXME: Consider IPTC data too */
+
+	/* Copy to the output file any extra markers that we want to
+	 * preserve */
+	jcopy_markers_execute (&srcinfo, &dstinfo, JCOPYOPT_DEFAULT);
+
+	/* Execute image transformation, if any */
+	jtransform_execute_transformation (&srcinfo,
+					   &dstinfo,
+					   src_coef_arrays,
+					   &transformoption);
+
+	/* Finish compression and release memory */
+	jpeg_finish_compress (&dstinfo);
+	jpeg_destroy_compress (&dstinfo);
+	(void) jpeg_finish_decompress (&srcinfo);
+	jpeg_destroy_decompress (&srcinfo);
+	g_free (jsrcerr.filename);
+
+	/* Close files */
+	fclose (input_file);
+	fclose (output_file);
+
+	return TRUE;
+}
+
+static gboolean
+_save_any_as_jpeg (EomImage *image, const char *file, EomImageSaveInfo *source,
+		   EomImageSaveInfo *target, GError **error)
+{
+	EomImagePrivate *priv;
+	GdkPixbuf *pixbuf;
+	struct jpeg_compress_struct cinfo;
+	guchar *buf = NULL;
+	guchar *ptr;
+	guchar *pixels = NULL;
+	JSAMPROW *jbuf;
+	int y = 0;
+	volatile int quality = 75; /* default; must be between 0 and 100 */
+	int i, j;
+	int w, h = 0;
+	int rowstride = 0;
+	FILE *outfile;
+	struct error_handler_data jerr;
+
+	g_return_val_if_fail (EOM_IS_IMAGE (image), FALSE);
+	g_return_val_if_fail (EOM_IMAGE (image)->priv->image != NULL, FALSE);
+
+	priv = image->priv;
+	pixbuf = priv->image;
+
+	rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+	w = gdk_pixbuf_get_width (pixbuf);
+	h = gdk_pixbuf_get_height (pixbuf);
+
+	/* no image data? abort */
+	pixels = gdk_pixbuf_get_pixels (pixbuf);
+	g_return_val_if_fail (pixels != NULL, FALSE);
+
+	outfile = fopen (file, "wb");
+	if (outfile == NULL) {
+		g_set_error (error,             /* FIXME: Better error message */
+			     GDK_PIXBUF_ERROR,
+			     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+			     _("Couldn't create temporary file for saving: %s"),
+			     file);
+		return FALSE;
+	}
+
+	/* allocate a small buffer to convert image data */
+	buf = g_try_malloc (w * 3 * sizeof (guchar));
+	if (!buf) {
+		g_set_error (error,
+			     GDK_PIXBUF_ERROR,
+			     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+			     _("Couldn't allocate memory for loading JPEG file"));
+		fclose (outfile);
+		return FALSE;
+	}
+
+	/* set up error handling */
+	jerr.filename = (char *) file;<--- Variable 'jerr.filename' is assigned a value that is never used.
+	cinfo.err = jpeg_std_error (&(jerr.pub));
+	jerr.pub.error_exit = fatal_error_handler;
+	jerr.pub.output_message = output_message_handler;
+	jerr.error = error;<--- Variable 'jerr.error' is assigned a value that is never used.
+
+	/* setup compress params */
+	jpeg_create_compress (&cinfo);
+	jpeg_stdio_dest (&cinfo, outfile);
+	cinfo.image_width      = w;
+	cinfo.image_height     = h;
+	cinfo.input_components = 3;
+	cinfo.in_color_space   = JCS_RGB;
+
+	/* error exit routine */
+	if (sigsetjmp (jerr.setjmp_buffer, 1)) {
+		g_free (buf);
+		fclose (outfile);
+		jpeg_destroy_compress (&cinfo);
+		return FALSE;
+	}
+
+	/* set desired jpeg quality if available */
+	if (target != NULL && target->jpeg_quality >= 0.0) {
+		quality = (int) MIN (target->jpeg_quality, 1.0) * 100;
+	}
+
+	/* set up jepg compression parameters */
+	jpeg_set_defaults (&cinfo);
+	jpeg_set_quality (&cinfo, quality, TRUE);
+	jpeg_start_compress (&cinfo, TRUE);
+
+	/* write EXIF/IPTC data explicitly */
+#if HAVE_EXIF
+	/* exif_chunk and exif are mutally exclusvie, this is what we assure here */
+	g_assert (priv->exif_chunk == NULL);
+	if (priv->exif != NULL)
+	{
+		unsigned char *exif_buf;
+		unsigned int   exif_buf_len;
+
+		exif_data_save_data (priv->exif, &exif_buf, &exif_buf_len);
+		jpeg_write_marker (&cinfo, 0xe1, exif_buf, exif_buf_len);
+		g_free (exif_buf);
+	}
+#else
+	if (priv->exif_chunk != NULL) {
+		jpeg_write_marker (&cinfo, JPEG_APP0+1, priv->exif_chunk, priv->exif_chunk_len);
+	}
+#endif
+	/* FIXME: Consider IPTC data too */
+
+	/* get the start pointer */
+	ptr = pixels;
+	/* go one scanline at a time... and save */
+	i = 0;
+	while (cinfo.next_scanline < cinfo.image_height) {
+		/* convert scanline from ARGB to RGB packed */
+		for (j = 0; j < w; j++)
+			memcpy (&(buf[j*3]), &(ptr[i*rowstride + j*(rowstride/w)]), 3);
+
+		/* write scanline */
+		jbuf = (JSAMPROW *)(&buf);
+		jpeg_write_scanlines (&cinfo, jbuf, 1);
+		i++;
+		y++;
+
+	}
+
+	/* finish off */
+	jpeg_finish_compress (&cinfo);
+	jpeg_destroy_compress(&cinfo);
+	g_free (buf);
+
+	fclose (outfile);
+
+	return TRUE;
+}
+
+gboolean
+eom_image_jpeg_save_file (EomImage *image, const char *file,
+			  EomImageSaveInfo *source, EomImageSaveInfo *target,
+			  GError **error)
+{
+	EomJpegSaveMethod method = EOM_SAVE_NONE;
+	gboolean source_is_jpeg = FALSE;
+	gboolean target_is_jpeg = FALSE;
+        gboolean result;
+
+	g_return_val_if_fail (source != NULL, FALSE);
+
+	source_is_jpeg = !g_ascii_strcasecmp (source->format, EOM_FILE_FORMAT_JPEG);
+
+	/* determine which method should be used for saving */
+	if (target == NULL) {
+		if (source_is_jpeg) {
+			method = EOM_SAVE_JPEG_AS_JPEG;
+		}
+	}
+	else {
+		target_is_jpeg = !g_ascii_strcasecmp (target->format, EOM_FILE_FORMAT_JPEG);
+
+		if (source_is_jpeg && target_is_jpeg) {
+			if (target->jpeg_quality < 0.0) {
+				method = EOM_SAVE_JPEG_AS_JPEG;
+			}
+			else {
+				/* reencoding is required, cause quality is set */
+				method = EOM_SAVE_ANY_AS_JPEG;
+			}
+		}
+		else if (!source_is_jpeg && target_is_jpeg) {
+			method = EOM_SAVE_ANY_AS_JPEG;
+		}
+	}
+
+	switch (method) {
+	case EOM_SAVE_JPEG_AS_JPEG:
+		result = _save_jpeg_as_jpeg (image, file, source, target, error);
+		break;
+	case EOM_SAVE_ANY_AS_JPEG:
+		result = _save_any_as_jpeg (image, file, source, target, error);
+		break;
+	default:
+		result = FALSE;
+	}
+
+	return result;
+}
+#endif
+
+
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/index.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/index.html new file mode 100644 index 0000000..3a625cd --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/index.html @@ -0,0 +1,247 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
cut-n-paste/toolbar-editor/egg-editable-toolbar.c
228variableScope398styleThe scope of the variable 'action' can be reduced.
229variableScope398styleThe scope of the variable 'action_name' can be reduced.
471shadowVariable398styleLocal variable 'screen' shadows outer variable
789variableScope398styleThe scope of the variable 'type' can be reduced.
863variableScope398styleThe scope of the variable 'string' can be reduced.
897shadowVariable398styleLocal variable 'action' shadows outer variable
1228variableScope398styleThe scope of the variable 'n_items' can be reduced.
1373variableScope398styleThe scope of the variable 'children' can be reduced.
1479variableScope398styleThe scope of the variable 'l' can be reduced.
1479variableScope398styleThe scope of the variable 'n_items' can be reduced.
cut-n-paste/toolbar-editor/egg-toolbar-editor.c
620unreadVariable563styleVariable 'y' is assigned a value that is never used.
cut-n-paste/toolbar-editor/egg-toolbars-model.c
270nullPointerRedundantCheck476warningEither the condition 'node!=NULL' is redundant or there is possible null pointer dereference: item_node.
270ctunullpointer476warningNull pointer dereference: item_node
288nullPointerRedundantCheck476warningEither the condition 'node!=NULL' is redundant or there is possible null pointer dereference: toolbar_node.
288ctunullpointer476warningNull pointer dereference: toolbar_node
309nullPointerRedundantCheck476warningEither the condition 'toolbar_node!=NULL' is redundant or there is possible null pointer dereference: toolbar_node.
325nullPointerRedundantCheck476warningEither the condition 'toolbar_node!=NULL' is redundant or there is possible null pointer dereference: toolbar_node.
753variableScope398styleThe scope of the variable 'node' can be reduced.
831variableScope398styleThe scope of the variable 'ipos' can be reduced.
916nullPointerRedundantCheck476warningEither the condition 'item!=NULL' is redundant or there is possible null pointer dereference: item.
923ctunullpointer476warningNull pointer dereference: model
936nullPointerRedundantCheck476warningEither the condition 'toolbar!=NULL' is redundant or there is possible null pointer dereference: toolbar.
jpegutils/transupp-6b.c
137variableScope398styleThe scope of the variable 'compptr' can be reduced.
187variableScope398styleThe scope of the variable 'compptr' can be reduced.
257variableScope398styleThe scope of the variable 'compptr' can be reduced.
305variableScope398styleThe scope of the variable 'compptr' can be reduced.
369variableScope398styleThe scope of the variable 'compptr' can be reduced.
434variableScope398styleThe scope of the variable 'compptr' can be reduced.
538variableScope398styleThe scope of the variable 'compptr' can be reduced.
704variableScope398styleThe scope of the variable 'itemp' can be reduced.
924variableScope398styleThe scope of the variable 'm' can be reduced.
jpegutils/transupp-8a.h
162unknownMacroerrorThere is an unknown macro here somewhere. Configuration is required. If EXTERN is a macro then please configure it.
src/eom-close-confirmation-dialog.c
317variableScope398styleThe scope of the variable 'wg' can be reduced.
454variableScope398styleThe scope of the variable 'width' can be reduced.
455variableScope398styleThe scope of the variable 'ratio' can be reduced.
src/eom-error-message-area.c
48variableScope398styleThe scope of the variable 'secondary_markup' can be reduced.
50variableScope398styleThe scope of the variable 'secondary_label' can be reduced.
src/eom-exif-util.c
204variableScope398styleThe scope of the variable 'buf_ptr' can be reduced.
228variableScope398styleThe scope of the variable 'buf_ptr' can be reduced.
src/eom-file-chooser.c
145variableScope398styleThe scope of the variable 'filter' can be reduced.
147variableScope398styleThe scope of the variable 'mime_types' can be reduced.
147variableScope398styleThe scope of the variable 'pattern' can be reduced.
248variableScope398styleThe scope of the variable 'bytes' can be reduced.
249variableScope398styleThe scope of the variable 'pixels' can be reduced.
250variableScope398styleThe scope of the variable 'bytes_str' can be reduced.
251variableScope398styleThe scope of the variable 'width' can be reduced.
252variableScope398styleThe scope of the variable 'height' can be reduced.
382knownConditionTrueFalse571styleCondition 'pixbuf!=NULL' is always true
src/eom-image-jpeg.c
209unreadVariable563styleVariable 'jsrcerr.error' is assigned a value that is never used.
215unreadVariable563styleVariable 'jdsterr.filename' is assigned a value that is never used.
219unreadVariable563styleVariable 'jdsterr.error' is assigned a value that is never used.
356variableScope398styleThe scope of the variable 'jbuf' can be reduced.
401unreadVariable563styleVariable 'jerr.filename' is assigned a value that is never used.
405unreadVariable563styleVariable 'jerr.error' is assigned a value that is never used.
src/eom-image.c
628variableScope398styleThe scope of the variable 'p' can be reduced.
1409variableScope398styleThe scope of the variable 'trans' can be reduced.
1410variableScope398styleThe scope of the variable 'inverse' can be reduced.
1440variableScope398styleThe scope of the variable 'tmp_file' can be reduced.
1958knownConditionTrueFalse571styleCondition '!broken_filenames' is always true
2221variableScope398styleThe scope of the variable 'mime_types' can be reduced.
2222variableScope398styleThe scope of the variable 'i' can be reduced.
2252shadowVariable398styleLocal variable 'supported_mime_types' shadows outer variable
src/eom-jobs.c
915variableScope398styleThe scope of the variable 'src' can be reduced.
915variableScope398styleThe scope of the variable 'dest' can be reduced.
916variableScope398styleThe scope of the variable 'filename' can be reduced.
916variableScope398styleThe scope of the variable 'dest_filename' can be reduced.
src/eom-list-store.c
253variableScope398styleThe scope of the variable 'thumbnail' can be reduced.
413shadowVariable398styleLocal variable 'image' shadows outer variable
471variableScope398styleThe scope of the variable 'child' can be reduced.
551variableScope398styleThe scope of the variable 'file_info' can be reduced.
src/eom-metadata-details.c
81unusedStructMember563stylestruct member 'ExifTagCategory::id' is never used.
318variableScope398styleThe scope of the variable 'tree_path' can be reduced.
src/eom-metadata-reader.c
31unknownMacroerrorThere is an unknown macro here somewhere. Configuration is required. If G_DEFINE_INTERFACE is a macro then please configure it.
src/eom-print-image-setup.c
688variableScope398styleThe scope of the variable 'pixbuf' can be reduced.
src/eom-properties-dialog.c
148variableScope398styleThe scope of the variable 'mime_str' can be reduced.
src/eom-resources.c
10unusedStructMember563styleunion member 'Anonymous0::alignment' is never used.
10unusedStructMember563styleunion member 'Anonymous0::ptr' is never used.
592unusedStructMember563styleunion member 'Anonymous0::alignment' is never used.
592unusedStructMember563styleunion member 'Anonymous0::ptr' is never used.
src/eom-save-as-dialog-helper.c
53nullPointerRedundantCheck476warningEither the condition 'data!=NULL' is redundant or there is possible null pointer dereference: data.
89nullPointerRedundantCheck476warningEither the condition 'data!=NULL' is redundant or there is possible null pointer dereference: data.
112nullPointerRedundantCheck476warningEither the condition 'data!=NULL' is redundant or there is possible null pointer dereference: data.
277nullPointerRedundantCheck476warningEither the condition 'data!=NULL' is redundant or there is possible null pointer dereference: data.
280nullPointerRedundantCheck476warningEither the condition 'data!=NULL' is redundant or there is possible null pointer dereference: data.
283nullPointerRedundantCheck476warningEither the condition 'data!=NULL' is redundant or there is possible null pointer dereference: data.
285nullPointerRedundantCheck476warningEither the condition 'data!=NULL' is redundant or there is possible null pointer dereference: data.
287nullPointerRedundantCheck476warningEither the condition 'data!=NULL' is redundant or there is possible null pointer dereference: data.
297nullPointerRedundantCheck476warningEither the condition 'data!=NULL' is redundant or there is possible null pointer dereference: data.
src/eom-scroll-view.c
1039selfAssignment398warningRedundant assignment of 'yofs' to itself.
1044selfAssignment398warningRedundant assignment of 'xofs' to itself.
src/eom-thumb-view.c
408variableScope398styleThe scope of the variable 'path' can be reduced.
445variableScope398styleThe scope of the variable 'image' can be reduced.
446variableScope398styleThe scope of the variable 'file' can be reduced.
535variableScope398styleThe scope of the variable 'extra_info' can be reduced.
879variableScope398styleThe scope of the variable 'path' can be reduced.
953variableScope398styleThe scope of the variable 'list' can be reduced.
src/eom-uri-converter.c
329variableScope398styleThe scope of the variable 'token' can be reduced.
626nullPointerRedundantCheck476warningEither the condition 'file!=NULL' is redundant or there is possible null pointer dereference: file.
src/eom-util.c
87variableScope398styleThe scope of the variable 'valid_bytes' can be reduced.
211variableScope398styleThe scope of the variable 'file' can be reduced.
src/eom-window.c
577unreadVariable563styleVariable 'show_image_collection' is assigned a value that is never used.
2222variableScope398styleThe scope of the variable 'dialog' can be reduced.
2390variableScope398styleThe scope of the variable 'dialog' can be reduced.
3235shadowArgument398styleLocal variable 'action' shadows outer argument
3276variableScope398styleThe scope of the variable 'file' can be reduced.
3277variableScope398styleThe scope of the variable 'file_info' can be reduced.
3279variableScope398styleThe scope of the variable 'image' can be reduced.
3308variableScope398styleThe scope of the variable 'image' can be reduced.
3469variableScope398styleThe scope of the variable 'img' can be reduced.
3471variableScope398styleThe scope of the variable 'response' can be reduced.
4178variableScope398styleThe scope of the variable 'file_list' can be reduced.
4179variableScope398styleThe scope of the variable 'window' can be reduced.
4704unreadVariable563styleVariable 'screen' is assigned a value that is never used.
5386variableScope398styleThe scope of the variable 'i' can be reduced.
5387variableScope398styleThe scope of the variable 'image' can be reduced.
+
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/stats.html b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/stats.html new file mode 100644 index 0000000..9f4c344 --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/stats.html @@ -0,0 +1,108 @@ + + + + + + Cppcheck - HTML report - eom + + + + + + + +
+

Top 10 files for error severity, total findings: 2
+   1  src/eom-metadata-reader.c
+   1  jpegutils/transupp-8a.h
+

+

Top 10 files for warning severity, total findings: 21
+   9  src/eom-save-as-dialog-helper.c
+   9  cut-n-paste/toolbar-editor/egg-toolbars-model.c
+   2  src/eom-scroll-view.c
+   1  src/eom-uri-converter.c
+

+

Top 10 files for style severity, total findings: 92
+   15  src/eom-window.c
+   10  cut-n-paste/toolbar-editor/egg-editable-toolbar.c
+   9   src/eom-file-chooser.c
+   9   jpegutils/transupp-6b.c
+   8   src/eom-image.c
+   6   src/eom-thumb-view.c
+   6   src/eom-image-jpeg.c
+   4   src/eom-resources.c
+   4   src/eom-list-store.c
+   4   src/eom-jobs.c
+

+ +
+ + + diff --git a/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/style.css b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/style.css new file mode 100644 index 0000000..c39571c --- /dev/null +++ b/2020-07-13-084614-7902-cppcheck@c331ec988f54_master/style.css @@ -0,0 +1,149 @@ + +body { + font: 13px Arial, Verdana, Sans-Serif; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +#footer > p { + margin: 4px; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + border: 1px dotted black; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #B6B6B4; +} + +.inconclusive2 { + background-color: #B6B6B4; + border: 1px dotted black; + display: inline-block; + margin-left: 4px; +} + +div.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +div.verbose div.content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid black; + background-color: #FFFFCC; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +#header { + border-bottom: thin solid #aaa; +} + +#menu { + float: left; + margin-top: 5px; + text-align: left; + width: 150px; + /*height: 75%;*/ + position: fixed; + overflow: auto; + z-index: 1; +} + +#menu_index { + float: left; + margin-top: 5px; + padding-left: 5px; + text-align: left; + width: 300px; + /*height: 75%;*/ + position: fixed; + overflow: auto; + z-index: 1; +} + +#menu > a { + display: block; + margin-left: 10px; + font: 12px; + z-index: 1; +} + +#filename { + margin-left: 10px; + font: 12px; + z-index: 1; +} + +.highlighttable { + background-color:white; + z-index: 10; + position: relative; + margin: -10 px; +} + +#content { + background-color: white; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + float: left; + margin: 5px; + margin-left: 10px; + padding: 0 10px 10px 10px; + width: 80%; + padding-left: 150px; +} + +#content_index { + background-color: white; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + float: left; + margin: 5px; + margin-left: 10px; + padding: 0 10px 10px 10px; + width: 80%; + padding-left: 300px; +} + +.linenos { + border-right: thin solid #aaa; + color: lightgray; + padding-right: 6px; +} + +#footer { + border-top: thin solid #aaa; + clear: both; + font-size: 90%; + margin-top: 5px; +} + +#footer ul { + list-style-type: none; + padding-left: 0; +} -- cgit v1.2.1