diff --git a/README.md b/README.md index bed80d7..c062c9a 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Intel Mac, jiná architektura nebo úpravy kódu → [sestavení ze zdroje](#ses Hause): cvičení, nápovědy, vokabeltraining - **Správa počítačových sítí** — 1. ročník, 27 lekcí (VLSM + teorie a kvízy); ročníky 2–4 jsou zamčené -- **Technické vybavení** — 3 lekce (architektura, historie, bit/byte) +- **Technické vybavení** — 9 lekcí (architektura, historie, data v počítači, digitalizace zvuku) - **Český jazyk a literatura** — mluvnice (20 cvičení) a maturitní četba (82 knih: zápisky, kvíz, sestavení děje); literární teorie je zatím zamčená - statistiky, hledání (lupa nebo `Cmd/Ctrl+K`), 10 témat, tmavý/světlý režim, čeština/angličtina @@ -259,7 +259,7 @@ Intel Mac, another architecture, or hacking on the code → exercises, hints, vocabulary training - **Computer networks** — year 1, 27 lessons (VLSM + theory/quizzes); years 2–4 are locked -- **Computer hardware** — 3 lessons (architecture, history, bit/byte) +- **Computer hardware** — 9 lessons (architecture, history, data representation, digitizing sound) - **Czech language** — grammar (20 exercises) and required reading (82 books: notes, quiz, plot ordering); literature theory is still locked - statistics, search (magnifier or `Cmd/Ctrl+K`), 10 palettes, dark/light mode, Czech/English diff --git a/data/changelog.txt b/data/changelog.txt index c7f47fe..d8e83c8 100644 --- a/data/changelog.txt +++ b/data/changelog.txt @@ -6,6 +6,10 @@ # cs: bullet # en: bullet +--- 2026-09-25 +cs: Technické vybavení: pět lekcí o digitalizaci zvuku (vzorkování, kvantování, PCM) +en: Hardware: five lessons on digitizing sound (sampling, quantization, PCM) + --- 2026-09-23 cs: Repozitář se jmenuje Graduately; instalátory a updater míří tam cs: Balíčky a instalátory se jmenují graduately-* (už ne maturita-*) diff --git a/scripts/extract-android-content.py b/scripts/extract-android-content.py index b8147aa..d7097ce 100644 --- a/scripts/extract-android-content.py +++ b/scripts/extract-android-content.py @@ -1085,7 +1085,7 @@ def main() -> int: }) hw_lessons = [] - for i in range(1, 5): + for i in range(1, 10): hw_lessons.append({ "id": i, "titleKey": f"hw_unit{i}", diff --git a/src/hw.c b/src/hw.c index 9695a01..44c223b 100644 --- a/src/hw.c +++ b/src/hw.c @@ -7,6 +7,11 @@ NetLesson hw_lessons[HW_LESSONS] = { { .n_slides = HW2_SLIDES, .unit_page = "hwunit2", .ex_page = "hwex2" }, { .n_slides = HW3_SLIDES, .unit_page = "hwunit3", .ex_page = "hwex3" }, { .n_slides = HW4_SLIDES, .unit_page = "hwunit4", .ex_page = "hwex4" }, + { .n_slides = HW5_SLIDES, .unit_page = "hwunit5", .ex_page = "hwex5" }, + { .n_slides = HW6_SLIDES, .unit_page = "hwunit6", .ex_page = "hwex6" }, + { .n_slides = HW7_SLIDES, .unit_page = "hwunit7", .ex_page = "hwex7" }, + { .n_slides = HW8_SLIDES, .unit_page = "hwunit8", .ex_page = "hwex8" }, + { .n_slides = HW9_SLIDES, .unit_page = "hwunit9", .ex_page = "hwex9" }, }; void hw_rail_theme_reset(void); @@ -253,7 +258,8 @@ void hw_add_node(GtkFixed *fixed, int index) { GtkWidget *name; char *text; static const char *unit_keys[HW_LESSONS] = { - "hw_unit1", "hw_unit2", "hw_unit3", "hw_unit4" + "hw_unit1", "hw_unit2", "hw_unit3", "hw_unit4", + "hw_unit5", "hw_unit6", "hw_unit7", "hw_unit8", "hw_unit9" }; card = gtk_button_new(); @@ -979,3 +985,346 @@ GtkWidget *build_hw_unit4_exercise_page(void) { return build_hw_mcq_page(3, "hwunit4", "hw_ex4_title", "hw_quiz4_head", qs, hints, 4); } + +GtkWidget *build_hw_unit5_page(void) { + static const NetSlide slides[HW5_SLIDES] = { + { + "1 / 2 • Signál", "Analogový a digitální zvuk", + "Tip: analog je spojitý, digitál je posloupnost čísel.", + { + "Analogový zvuk je spojitý signál – v každém okamžiku " + "má nějakou hodnotu.", + "Digitální zvuk je posloupnost čísel, která ten signál " + "popisují.", + "Z mikrofonu vychází analogové napětí, do reproduktoru " + "musí zase jít spojitý signál.", + "Počítač umí uložit jen čísla, proto se zvuk digitalizuje.", + NULL, + }, + }, + { + "2 / 2 • Převod", "A/D a D/A převodník", + "Tip: ADC dovnitř, DAC ven. Digitalizace = vzorkování + kvantování.", + { + "A/D převodník (ADC) převede analogový signál na čísla.", + "D/A převodník (DAC) z čísel znovu složí spojitý signál.", + "Digitalizace má dva kroky: vzorkování a kvantování.", + "Vzorkování určí, kdy se hodnota změří.", + "Kvantování určí, na kolik hladin se amplituda zaokrouhlí.", + NULL, + }, + }, + }; + + return build_hw_unit_page(&hw_lessons[4], "hw_unit5", "hw_unit5_sub", + slides, HW5_SLIDES); +} + +GtkWidget *build_hw_unit5_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Co je analogový zvuk?", + {"Posloupnost celých čísel", + "Spojitý signál s hodnotou v každém okamžiku", + "Jen název souboru WAV", + "Jen bit v paměti"}, + 4, 1}, + {"Co dělá A/D převodník (ADC)?", + {"Převádí analogový signál na čísla", + "Zesiluje jen reproduktor", + "Maže vysoké tóny po uložení", + "Počítá jen velikost souboru"}, + 4, 0}, + {"Jaké jsou dva hlavní kroky digitalizace zvuku?", + {"Komprese a tisk", + "Vzorkování a kvantování", + "Šifrování a záloha", + "Násobení a dělení"}, + 4, 1}, + {"Co dělá D/A převodník (DAC)?", + {"Z čísel znovu skládá spojitý signál", + "Měří jen vzorkovací frekvenci", + "Ukládá zvuk jako text", + "Zvyšuje počet bitů v souboru"}, + 4, 0}, + }; + static const char *hints[] = { + "Analog = spojitý signál", + "ADC převádí analog na čísla", + "Digitalizace = vzorkování + kvantování", + "DAC skládá z čísel spojitý signál", + }; + return build_hw_mcq_page(4, "hwunit5", "hw_ex5_title", "hw_quiz5_head", + qs, hints, 4); +} + +GtkWidget *build_hw_unit6_page(void) { + static const NetSlide slides[HW6_SLIDES] = { + { + "1 / 2 • Vzorky", "Vzorkování", + "Tip: vzorkovací frekvence fs = počet vzorků za sekundu (Hz).", + { + "Vzorkování měří velikost signálu v pravidelných " + "okamžicích.", + "Mezi vzorky se hodnota neukládá.", + "Vzorkovací frekvence fs je počet vzorků za sekundu.", + "Jednotka je hertz (Hz). 1 kHz = 1000 vzorků za sekundu.", + "Vyšší fs zachytí rychlejší změny, tedy vyšší tóny.", + NULL, + }, + }, + { + "2 / 2 • Nyquist", "Nyquistův–Shannonův teorém", + "Tip: fs musí být vyšší než 2 × fmax. Nyquistova frekvence je fs / 2.", + { + "Pro věrnou rekonstrukci musí být fs vyšší než dvojnásobek " + "nejvyšší frekvence ve signálu.", + "Nyquistova frekvence je fs / 2 – vyšší tón už záznam neunese.", + "Člověk slyší zhruba do 20 kHz, dvojnásobek je 40 kHz.", + "CD proto používá 44,1 kHz: o něco víc než 40 kHz, " + "aby zbyl prostor pro filtr.", + NULL, + }, + }, + }; + + return build_hw_unit_page(&hw_lessons[5], "hw_unit6", "hw_unit6_sub", + slides, HW6_SLIDES); +} + +GtkWidget *build_hw_unit6_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Co je vzorkovací frekvence?", + {"Počet bitů v jednom vzorku", + "Počet vzorků za sekundu", + "Délka skladby v minutách", + "Počet kanálů (mono nebo stereo)"}, + 4, 1}, + {"V jakých jednotkách se udává vzorkovací frekvence?", + {"V bytech", "V hertzech", "Ve voltech", "V pixelech"}, + 4, 1}, + {"Co říká Nyquistův–Shannonův teorém?", + {"fs musí být vyšší než dvojnásobek nejvyšší frekvence", + "fs musí být vždy 8 kHz", + "Stačí jeden vzorek na celou skladbu", + "Bitová hloubka musí být 1"}, + 4, 0}, + {"Proč má audio CD vzorkovací frekvenci 44,1 kHz?", + {"Protože byte má 8 bitů", + "Sluch sahá asi do 20 kHz a fs musí být vyšší než dvojnásobek", + "Protože stereo má dva kanály", + "Protože minutu tvoří 60 sekund"}, + 4, 1}, + }; + static const char *hints[] = { + "fs = počet vzorků za sekundu", + "Jednotka vzorkovací frekvence je hertz", + "fs > 2 × fmax", + "20 kHz × 2 = 40 kHz, CD má 44,1 kHz", + }; + return build_hw_mcq_page(5, "hwunit6", "hw_ex6_title", "hw_quiz6_head", + qs, hints, 4); +} + +GtkWidget *build_hw_unit7_page(void) { + static const NetSlide slides[HW7_SLIDES] = { + { + "1 / 2 • Hladiny", "Kvantování", + "Tip: n bitů → 2ⁿ hladin. 8 bitů = 256, 16 bitů = 65 536.", + { + "Kvantování zaokrouhlí amplitudu každého vzorku " + "na nejbližší z konečného počtu hladin.", + "Počet hladin je 2ⁿ, kde n je bitová hloubka " + "(počet bitů na vzorek).", + "8 bitů dává 256 hladin, 16 bitů dává 65 536 hladin.", + "Vzorkování říká jak často, kvantování jak přesně.", + NULL, + }, + }, + { + "2 / 2 • Chyba", "Kvantizační chyba", + "Tip: víc bitů = jemnější hladiny, menší šum a větší soubor.", + { + "Kvantizační chyba je rozdíl mezi skutečnou hodnotou " + "a zvolenou hladinou.", + "V záznamu se projeví jako kvantizační šum.", + "Větší bitová hloubka hladiny zjemní a šum zmenší.", + "Audio CD používá 16 bitů na vzorek, studio často 24 bitů.", + "Vyšší hloubka také zvětší datový tok.", + NULL, + }, + }, + }; + + return build_hw_unit_page(&hw_lessons[6], "hw_unit7", "hw_unit7_sub", + slides, HW7_SLIDES); +} + +GtkWidget *build_hw_unit7_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Co je kvantování?", + {"Měření signálu v pravidelných okamžicích", + "Zaokrouhlení amplitudy na konečný počet hladin", + "Převod čísel zpět na analog", + "Komprese souboru MP3"}, + 4, 1}, + {"Kolik hladin má 8bitové kvantování?", + {"8", "16", "256", "65 536"}, + 4, 2}, + {"Kolik hladin má 16bitové kvantování?", + {"16", "256", "1 024", "65 536"}, + 4, 3}, + {"Co je kvantizační chyba?", + {"Rozdíl mezi skutečnou hodnotou a zvolenou hladinou", + "Příliš nízká vzorkovací frekvence", + "Počet kanálů ve stereu", + "Délka skladby v sekundách"}, + 4, 0}, + }; + static const char *hints[] = { + "Kvantování zaokrouhluje amplitudu na hladiny", + "8 bitů → 2⁸ = 256 hladin", + "16 bitů → 2¹⁶ = 65 536 hladin", + "Kvantizační chyba = rozdíl proti skutečné hodnotě", + }; + return build_hw_mcq_page(6, "hwunit7", "hw_ex7_title", "hw_quiz7_head", + qs, hints, 4); +} + +GtkWidget *build_hw_unit8_page(void) { + static const NetSlide slides[HW8_SLIDES] = { + { + "1 / 2 • PCM", "Pulzně kódová modulace", + "Tip: tok = fs × bity na vzorek × počet kanálů.", + { + "PCM uloží každý vzorek jako binární číslo.", + "Je to základní nekomprimovaný záznam (WAV, audio CD).", + "Datový tok = vzorkovací frekvence × bitová hloubka " + "× počet kanálů.", + "Mono má jeden kanál, stereo dva (levý a pravý).", + NULL, + }, + }, + { + "2 / 2 • Velikost", "Kolik dat zabere CD", + "Tip: komprese (MP3, AAC) soubor zmenší, ale část informace zahodí.", + { + "CD stereo: 44 100 Hz × 16 bit × 2 = 1 411 200 bit/s.", + "To je 176 400 B/s.", + "Za minutu je to 10 584 000 B, tedy přes 10 MB.", + "Delší záznam, vyšší fs, více bitů nebo více kanálů " + "soubor zvětší.", + "MP3 a AAC soubor zmenší za cenu ztráty části informace.", + NULL, + }, + }, + }; + + return build_hw_unit_page(&hw_lessons[7], "hw_unit8", "hw_unit8_sub", + slides, HW8_SLIDES); +} + +GtkWidget *build_hw_unit8_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Co je PCM?", + {"Každý vzorek uložený jako binární číslo", + "Jen komprimovaný formát MP3", + "Filtr před mikrofonem", + "Jednotka hlasitosti"}, + 4, 0}, + {"Jak se spočítá datový tok nekomprimovaného zvuku?", + {"fs + bity + kanály", + "fs × bitová hloubka × počet kanálů", + "jen délka skladby v minutách", + "počet hladin děleno dvěma"}, + 4, 1}, + {"Jaký je datový tok audio CD ve stereu?", + {"44 100 bit/s", "256 bit/s", "1 411 200 bit/s", "8 bit/s"}, + 4, 2}, + {"Co udělá komprese MP3 se záznamem?", + {"Zvětší soubor a přidá vzorky", + "Zmenší soubor a část informace zahodí", + "Změní jen název souboru", + "Převede digitál zpět na analog"}, + 4, 1}, + }; + static const char *hints[] = { + "PCM = vzorek jako binární číslo", + "tok = fs × bity × kanály", + "44 100 × 16 × 2 = 1 411 200 bit/s", + "MP3 soubor zmenší a část informace zahodí", + }; + return build_hw_mcq_page(7, "hwunit8", "hw_ex8_title", "hw_quiz8_head", + qs, hints, 4); +} + +GtkWidget *build_hw_unit9_page(void) { + static const NetSlide slides[HW9_SLIDES] = { + { + "1 / 2 • Aliasing", "Když je vzorkování moc řídké", + "Tip: aliasing vznikne před uložením a z hotových vzorků " + "už nejde spolehlivě odstranit.", + { + "Aliasing vznikne, když je fs příliš nízká a poruší se " + "Nyquistovo pravidlo.", + "Vysoká frekvence se v záznamu jeví jako nižší tón.", + "Příklad: tón 6 kHz vzorkovaný 8 kHz se jeví jako 2 kHz.", + "Antialiasingový filtr před převodníkem vysoké frekvence " + "ořízne.", + NULL, + }, + }, + { + "2 / 2 • Formáty", "Běžné parametry záznamu", + "Tip: vyšší fs a víc bitů znamená věrnější záznam a větší tok.", + { + "Audio CD: 44,1 kHz, 16 bitů, stereo.", + "Klasický telefonní hovor: 8 kHz a 8 bitů – řeč se vejde " + "do pásma do 4 kHz.", + "Studio často používá 48 nebo 96 kHz a 24 bitů.", + "Parametry se volí podle toho, co má záznam unést " + "a jak velký smí být.", + NULL, + }, + }, + }; + + return build_hw_unit_page(&hw_lessons[8], "hw_unit9", "hw_unit9_sub", + slides, HW9_SLIDES); +} + +GtkWidget *build_hw_unit9_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdy vzniká aliasing?", + {"Když je vzorkovací frekvence příliš nízká", + "Když má záznam 24 bitů", + "Když je soubor ve stereu", + "Když se použije D/A převodník"}, + 4, 0}, + {"K čemu je antialiasingový filtr?", + {"Zvětší bitovou hloubku po uložení", + "Před vzorkováním ořízne frekvence nad Nyquistovu", + "Spočítá datový tok", + "Převede mono na stereo"}, + 4, 1}, + {"Jaké parametry má audio CD?", + {"8 kHz, 8 bitů, mono", + "44,1 kHz, 16 bitů, stereo", + "96 kHz, 8 bitů, mono", + "1 kHz, 1 bit, stereo"}, + 4, 1}, + {"Proč telefonnímu hovoru stačí vzorkování 8 kHz?", + {"Řeč se vejde do pásma zhruba do 4 kHz", + "Telefon nahrává na audio CD", + "8 kHz je totéž co 44,1 kHz", + "Řeč nemá žádnou frekvenci"}, + 4, 0}, + }; + static const char *hints[] = { + "Aliasing = příliš nízká fs", + "Filtr ořízne frekvence nad fs / 2 ještě před vzorkováním", + "CD = 44,1 kHz, 16 bit, stereo", + "Pásmo řeči je do asi 4 kHz, proto stačí fs = 8 kHz", + }; + return build_hw_mcq_page(8, "hwunit9", "hw_ex9_title", "hw_quiz9_head", + qs, hints, 4); +} diff --git a/src/i18n.c b/src/i18n.c index 7c12555..69396e8 100644 --- a/src/i18n.c +++ b/src/i18n.c @@ -549,6 +549,41 @@ const TrEntry tr_ui[] = { "Quiz: integer and real"}, {"hw_quiz4_head", "Kvíz k celým a desetinným číslům", "Quiz on integers and floating-point numbers"}, + {"hw_unit5", "Analogový a digitální zvuk", "Analog and digital sound"}, + {"hw_unit5_sub", "2 snímky o převodu zvuku na čísla a pak kvíz.", + "2 slides about turning sound into numbers, then a quiz."}, + {"hw_ex5_title", "Kvíz: analog a digitál", + "Quiz: analog and digital"}, + {"hw_quiz5_head", "Kvíz k analogovému a digitálnímu zvuku", + "Quiz on analog and digital sound"}, + {"hw_unit6", "Vzorkování", "Sampling"}, + {"hw_unit6_sub", "2 snímky o vzorkovací frekvenci a Nyquistovi a pak kvíz.", + "2 slides about sample rate and Nyquist, then a quiz."}, + {"hw_ex6_title", "Kvíz: vzorkování", + "Quiz: sampling"}, + {"hw_quiz6_head", "Kvíz ke vzorkování zvuku", + "Quiz on sampling sound"}, + {"hw_unit7", "Kvantování", "Quantization"}, + {"hw_unit7_sub", "2 snímky o bitové hloubce a kvantizační chybě a pak kvíz.", + "2 slides about bit depth and quantization error, then a quiz."}, + {"hw_ex7_title", "Kvíz: kvantování", + "Quiz: quantization"}, + {"hw_quiz7_head", "Kvíz ke kvantování zvuku", + "Quiz on quantizing sound"}, + {"hw_unit8", "PCM a datový tok", "PCM and data rate"}, + {"hw_unit8_sub", "2 snímky o PCM a velikosti záznamu a pak kvíz.", + "2 slides about PCM and recording size, then a quiz."}, + {"hw_ex8_title", "Kvíz: PCM a datový tok", + "Quiz: PCM and data rate"}, + {"hw_quiz8_head", "Kvíz k PCM a datovému toku", + "Quiz on PCM and data rate"}, + {"hw_unit9", "Aliasing a parametry", "Aliasing and formats"}, + {"hw_unit9_sub", "2 snímky o aliasingu a běžných formátech a pak kvíz.", + "2 slides about aliasing and common formats, then a quiz."}, + {"hw_ex9_title", "Kvíz: aliasing a parametry", + "Quiz: aliasing and formats"}, + {"hw_quiz9_head", "Kvíz k aliasingu a parametrům záznamu", + "Quiz on aliasing and recording formats"}, {"czech_sub", "Vyberte oblast a začněte procvičovat.", "Pick an area and start practicing."}, {"Literatura", "Literatura", "Literature"}, diff --git a/src/main.c b/src/main.c index d74f4bc..7b2738a 100644 --- a/src/main.c +++ b/src/main.c @@ -391,6 +391,8 @@ static gboolean run_smoke_test(gpointer data) { "cetbaFuks", "cetbaFuksQuiz", "cetbaFuksDej", "hwunit1", "hwex1", "hwunit2", "hwex2", "hwunit3", "hwex3", "hwunit4", "hwex4", + "hwunit5", "hwex5", "hwunit6", "hwex6", "hwunit7", "hwex7", + "hwunit8", "hwex8", "hwunit9", "hwex9", "unit1", "unit2", "unit3", "u1e1", "u1e13", "u2e1", "u2e19", "u3e1", "u3e15", "u1vocab", "u2vocab", "u3vocab", @@ -533,6 +535,16 @@ void activate(GtkApplication *app, gpointer user_data) { gtk_stack_add_named(main_stack, build_hw_unit3_exercise_page(), "hwex3"); gtk_stack_add_named(main_stack, build_hw_unit4_page(), "hwunit4"); gtk_stack_add_named(main_stack, build_hw_unit4_exercise_page(), "hwex4"); + gtk_stack_add_named(main_stack, build_hw_unit5_page(), "hwunit5"); + gtk_stack_add_named(main_stack, build_hw_unit5_exercise_page(), "hwex5"); + gtk_stack_add_named(main_stack, build_hw_unit6_page(), "hwunit6"); + gtk_stack_add_named(main_stack, build_hw_unit6_exercise_page(), "hwex6"); + gtk_stack_add_named(main_stack, build_hw_unit7_page(), "hwunit7"); + gtk_stack_add_named(main_stack, build_hw_unit7_exercise_page(), "hwex7"); + gtk_stack_add_named(main_stack, build_hw_unit8_page(), "hwunit8"); + gtk_stack_add_named(main_stack, build_hw_unit8_exercise_page(), "hwex8"); + gtk_stack_add_named(main_stack, build_hw_unit9_page(), "hwunit9"); + gtk_stack_add_named(main_stack, build_hw_unit9_exercise_page(), "hwex9"); { typedef GtkWidget *(*NetBuilder)(void); static const struct { diff --git a/src/maturita.h b/src/maturita.h index 93c73f3..65e9ac1 100644 --- a/src/maturita.h +++ b/src/maturita.h @@ -113,11 +113,16 @@ extern char *app_progress_cetba; #define NET27_SLIDES 8 #define NET_LESSONS 27 #define HW_UNITS 10 -#define HW_LESSONS 4 +#define HW_LESSONS 9 #define HW_SLIDES 3 #define HW2_SLIDES 6 #define HW3_SLIDES 2 #define HW4_SLIDES 2 +#define HW5_SLIDES 2 +#define HW6_SLIDES 2 +#define HW7_SLIDES 2 +#define HW8_SLIDES 2 +#define HW9_SLIDES 2 typedef enum { THEME_CATPPUCCIN = 0, @@ -869,6 +874,16 @@ GtkWidget *build_hw_unit3_page(void); GtkWidget *build_hw_unit3_exercise_page(void); GtkWidget *build_hw_unit4_page(void); GtkWidget *build_hw_unit4_exercise_page(void); +GtkWidget *build_hw_unit5_page(void); +GtkWidget *build_hw_unit5_exercise_page(void); +GtkWidget *build_hw_unit6_page(void); +GtkWidget *build_hw_unit6_exercise_page(void); +GtkWidget *build_hw_unit7_page(void); +GtkWidget *build_hw_unit7_exercise_page(void); +GtkWidget *build_hw_unit8_page(void); +GtkWidget *build_hw_unit8_exercise_page(void); +GtkWidget *build_hw_unit9_page(void); +GtkWidget *build_hw_unit9_exercise_page(void); void draw_chip_icon(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer data); void draw_czech_flag(GtkDrawingArea *area, cairo_t *cr,