Ghostty GTK एप्लिकेशन को फिर से लिखा गया
(mitchellh.com)- Ghostty टीम ने GTK एप्लिकेशन को पूरी तरह से फिर से लिखा और GObject type system का सक्रिय रूप से उपयोग किया
- इस प्रक्रिया में Zig भाषा के साथ इंटीग्रेशन और Valgrind के जरिए memory issues की जांच ने महत्वपूर्ण भूमिका निभाई
- GObject system अपनाने से पहले की तुलना में memory management और custom widget implementation सरल हो गए
- Valgrind का उपयोग करने के परिणामस्वरूप, Ghostty की memory safety में बड़ा सुधार अनुभव किया गया
- नया Ghostty GTK अब source build का default बन गया है और इसे 1.2 release में शामिल किया जाएगा
परिचय
- Ghostty एक cross-platform terminal emulator है जो macOS, Linux, FreeBSD को सपोर्ट करता है
- हर platform पर native GUI framework का उपयोग करके इसे अलग बनाया गया है
- macOS: Swift और Xcode आधारित large-scale application
- Linux और BSD: GTK आधारित application, X11/Wayland आदि के साथ direct integration
- common core Zig में लिखा गया है और C ABI-compatible API प्रदान करता है
- मौजूदा संरचना में GTK application को फिर से लिखने का कारण मूल PR में देखा जा सकता है
- यह लेख मुख्य रूप से GObject type system के साथ integration और Valgrind से सत्यापित memory issues पर केंद्रित है
GObject type system और Zig
- GTK का उपयोग करने पर मूल रूप से GObject type system के साथ interface करना पड़ता है
- पहले GObject system से बचते हुए reference counting के बिना Zig objects और GObject objects के lifecycle को सीधे मिलाने की कोशिश की गई, लेकिन बार-बार memory release ठीक से न होने की समस्या आई
- उदाहरण: Zig की तरफ की memory free हो गई, लेकिन GTK की memory अभी भी जीवित थी, या इसका उल्टा बार-बार हुआ
- यह approach केवल correctness की समस्या नहीं थी, बल्कि GTK की खास सुविधाओं (event signals, property binding, actions) का उपयोग भी कठिन बना देती थी
- एक ठोस उदाहरण में config struct को reload करते समय उससे जुड़े सभी GUI elements को एकसमान तरीके से update होना चाहिए था, लेकिन यह प्रक्रिया जटिल और त्रुटिपूर्ण थी
- अब Zig
Configstruct को wrap करने वाले reference-countedGhosttyConfigGObject से इसे manage किया जाता है, और property change notifications के जरिए बदलाव पूरे application में स्वाभाविक रूप से फैल जाते हैं
- अब Zig
- custom GObject widgets बनाना भी आसान हो गया, जिससे Blueprint जैसी आधुनिक GTK UI technologies का उपयोग संभव हुआ
- हाल में Blueprint अपनाने से GTK titlebar tabs, animated bell border जैसी नई सुविधाएँ जोड़ना आसान हुआ
Valgrind, GTK, और Zig
- पूरे development process में Valgrind की मदद से memory leaks, undefined memory access जैसी समस्याओं की व्यवस्थित जांच की गई
- GTK application पर Valgrind चलाना कठिन है, और इसके लिए बड़े suppression files की जरूरत पड़ती है (80% GTK खुद, बाकी 3rd party libraries और GPU drivers)
- बार-बार की गई जांच से ऐसे जटिल memory bugs पहले ही पकड़े जा सके जो केवल कुछ स्थितियों में ही सामने आते हैं
- उदाहरण: अगर GObject
WeakRefको ठीक से initialize न किया जाए, तो target object बाद में free होने पर undefined memory access होता है, जिसे Valgrind ने पहले ही पकड़ लिया
- उदाहरण: अगर GObject
- वास्तविक अनुभव में, Zig codebase के अंदर कुल केवल 2 issues (1 leak, 1 undefined access) मिले, और वे भी 3rd party C API integration के दौरान हुए
- Zig के debug allocators और Valgrind integration features भी प्रभावी साबित हुए
- बाकी मिले memory issues अधिकतर C API boundaries और GObject system के जटिल lifecycle management से जुड़े थे
- निष्कर्षतः जटिल libraries के C API को सुरक्षित रूप से इस्तेमाल करने के लिए Valgrind जैसे tools जरूरी हैं
- Zig की memory safety को सहारा देने वाली सुविधाएँ केवल सैद्धांतिक चर्चा तक सीमित नहीं हैं, बल्कि व्यावहारिक project experience में भी प्रभावी साबित हुईं
निष्कर्ष
- यह Ghostty के GUI हिस्से को पांचवीं बार शुरुआत से फिर से बनाने का अनुभव था
- GLFW, macOS SwiftUI, macOS AppKit+SwiftUI, Linux GTK (procedural), Linux GTK+GObject type system के क्रम में
- बार-बार के rewrite process में हर बार नए सबक और तकनीकी विकास मिले
- इस अनुभव का कुछ हिस्सा macOS project में भी लागू करने की योजना है
- Ghostty GTK system maintainers के सक्रिय सहयोग पर भी जोर दिया गया
- नया फिर से लिखा गया Ghostty GTK एप्लिकेशन अब source build का default बन गया है, और इसे 1.2 stable release में लागू किया जाएगा
1 टिप्पणियां
Hacker News टिप्पणियाँ
मैंने सीधे GTK के साथ काम नहीं किया है, लेकिन आपकी बात सुनकर लगा कि यह Zig में Godot bindings बनाते समय आने वाली समस्याओं से बहुत मिलता-जुलता है। Godot में classes, virtual methods, properties, signals जैसे OOP concepts बहुत हैं। और यह एक C API देता है जो इन सभी concepts को संभाल सकता है और user-defined objects व properties बनाने देता है। यह engine objects की lifetime management खुद करता है, और reference-counted objects की tree structure भी है। खासकर lifetime issues को Zig idioms के हिसाब से एक optimal API में समेटने की कोशिश करते समय चीज़ें बहुत जटिल हो जाती हैं। इन्हीं चिंताओं के चलते मैंने oopz library भी बनाई। अभी API की स्थिति यही है, और एक वास्तविक उदाहरण यहाँ देखा जा सकता है। मैं Ghostty frontend को Godot extension के रूप में भी बनाकर देखना चाहता हूँ
यह अच्छा उदाहरण है कि अच्छी programming आखिरकार system द्वारा दिए गए तरीके के साथ तालमेल बिठाने में ही है। आप OOP या memory management के बारे में जो भी सोचें, अगर आप GTK का उपयोग करते हैं तो आपको किसी न किसी तरह GObject type system के साथ interface बनाना ही पड़ेगा। चाहें बचना चाहें, अंत में उससे बच नहीं सकते। लेकिन हमने बचने की कोशिश की, और उसका नतीजा यह हुआ कि reference-counted objects और non-reference objects की lifetimes को बाँधते समय पूरी तरह अव्यवस्था फैल गई। Ghostty GTK app में बार-बार ऐसे bugs आते थे जहाँ Zig memory free करने पर GTK memory free नहीं होती थी, या इसका उल्टा होता था
OOP और memory management पर मेरी राय अलग हो सकती है, लेकिन इस बात से सहमत हूँ कि GTK इस्तेमाल करने पर GObject type system में उलझना लगभग तय है। इसलिए मैंने तय किया कि सीधे GTK का उपयोग ही न करूँ। unified UI theme की अपनी value है, लेकिन मेरी नज़र में GTK के फायदे इतने बड़े नहीं हैं कि उनकी कीमत चुकाकर उन्हें अपनाया जाए। open source apps में GTK के आसपास काम करने के अनुभव से मुझे यक़ीन हो गया कि GTK और GObject की सोच मेरे स्वभाव से मेल नहीं खाती। GTK के अस्तित्व से मुझे दिक्कत नहीं है। मैं बस इसे न इस्तेमाल करने का विकल्प चुनता हूँ, और मेरे लिए वह ठीक है, लेकिन कुछ लोगों का यह मानना अजीब लगता है कि यह चुनाव मानो मेरा अधिकार ही नहीं है। यह कई GUI toolkits में से सिर्फ़ एक है, और तकनीकी रूप से बहुत polished toolkit है, फिर भी कभी-कभी लगता है कि अगर GTK का share थोड़ा कम होता, तो शायद वही polish किसी ऐसे toolkit पर लगती जिसकी बुनियादी संरचना बेहतर होती। बेशक, जो मुझे अच्छा लगता है वह सबके लिए अच्छा हो, यह ज़रूरी नहीं। मैं जानना चाहता हूँ कि GTK इस्तेमाल करने वालों में कितने लोग मजबूरी में करते हैं और कितने लोग इसे सचमुच सबसे बेहतरीन toolkit मानते हैं
एक दिलचस्प तथ्य यह है कि Ghostty और कुछ अन्य GTK apps में अगर mouse window के बाहर जाकर वापस अंदर आता है, तो पहला scroll click अनदेखा हो जाता है। इसकी वजह 2015 में पहली बार रिपोर्ट हुआ एक बहुत पुराना bug है। Bug link। अभी तक इसे ठीक करने की कोई योजना नहीं है, और maintainer का रुख़ है कि Wayland का इंतज़ार किया जाए
“मैंने हर चरण को Valgrind से verify किया” — यह सुनकर लगा कि बात बहुत obvious है, लेकिन सच कहूँ तो मैंने खुद ऐसा कभी नहीं किया, और दूसरे developers को भी ऐसा करते कम ही देखा है। आमतौर पर Valgrind तभी इस्तेमाल होता है जब कोई specific bug या performance regression सामने आए। अगर development के दौरान सक्रिय रूप से Valgrind (खासकर Memcheck, Helgrind) जैसे tools का उपयोग किया जाए, तो tool की stability बहुत बढ़ सकती है, और bugs भी introduce होते ही पकड़े जा सकते हैं, जिससे बाद में सैकड़ों commits खंगालने की मेहनत कम हो सकती है
Ghostty इस्तेमाल करते समय Mac पर nano में multi-line paste न कर पाना बहुत असुविधाजनक है। लगता है यह इस बात पर निर्भर करता है कि terminal “bracketed pasting” को कैसे handle करता है, लेकिन अजीब बात यह है कि iTerm2 या Terminal में यह समस्या नहीं होती
सोच रहा हूँ कि अगर Zig की जगह Rust का उपयोग किया जाता, तो क्या memory errors रुक जातीं। ज़्यादातर समस्याएँ Zig/C interop से आईं, इसलिए लगता है Rust में भी कुछ ऐसी ही रहतीं। Go developer के नज़रिए से अंदाज़ा लगा रहा हूँ, लेकिन जब बड़े पैमाने पर C के साथ interop करना हो, तब क्या कोई ऐसी भाषा है जो और अधिक safety tools देती हो, यह जानने की उत्सुकता है
Ghostty जैसे GPU-आधारित apps (Alacritty, WezTerm, Zed आदि) इस्तेमाल करते हुए वे मुझे तेज़ और बेहतर लगे। लेकिन विडंबना यह है कि ऐसे apps Nvidia drivers की सीमाओं को और साफ़ कर देते हैं। पहले GPU का उपयोग बहुत कम करता था, इसलिए पता नहीं चला, लेकिन Regolith i3wm जैसे compositor-रहित environments और sway/Wayland environments दोनों में screen sharing, sleep से resume, crashes जैसी चीज़ों में Nvidia drivers बहुत खराब निकले। कई versions (550/560/575/580) बदलकर भी देखा, सब एक जैसे थे। हाल ही में समझ आया कि वे पहले से ही इतने खराब थे
मैं GTK type system को code पर हावी हुए बिना एक बड़ा app बना सका। लेकिन उसके बदले classes inherit या extend करने के बजाय, मैंने components के बीच सब कुछ केवल lambdas bind करके जोड़ा। नतीजा इतना गड़बड़ नहीं था, लेकिन जो developer पारंपरिक GTK style के आदी हों, उन्हें यह उलझनभरा लग सकता था
मुझे Ghostty को लेकर यह बढ़ा-चढ़ाकर दिखाई देने वाला उत्साह समझ नहीं आता। UI में tabs और context menu से आगे बहुत कुछ नहीं है, तो क्या इस तरह के integration work और rewrite का इतना मूल्य है? अंदाज़ा है कि शायद यह iTerm2 जैसी शक्तिशाली GUI environment तक बढ़ना चाहता है। Kitty OpenGL से tabs खुद draw करता है, इसलिए पूरी customization संभव है, और किसी जटिल framework में integrate करने में समय बर्बाद करने के बजाय वह बेहद practical features जल्दी लागू कर देता है, जैसे last command result को pager में wrap करके output देना। Kitty में remote support भी अच्छा है