5/20/2013

Ekran kırpma aracı da kullanıma hazır.


Merhabalar, bu hafta uygulamaya yeni bir özellik ekledim. Bu özellik projenin ilk taslağında olmayan bir özellikti, danışmanıma önerdiğimde beğendi ve eklemeye karar verdik. Öncelikle Cairo grafik kütüphanesiyle uğraşmam gerekiyordu, bu da bilmediğimden gözümü korkutuyordu fakat Cairo'nun tam da olması gereken basitlikte ve harika işler yapabilen bir kütüphane olduğunu öğrendim, bu da işimi oldukça kolaylaştırdı. Aracı yazarken yaptıklarım ekran görüntüsüne biraz şeffaflık ekleyip tam ekran bir pencereye basmak, imleç ile seçilen dikdörtgene ekran görüntüsü şeffaflık eklemeden tekrar basmak ve etrafına kesikli bir çerçeve eklemek, böyle anlatıyorum ama yaptıklarım gerçekten de paint_with_alpha() rectangle() set_border_width() gibi fonksiyonlarla tam da anlattığım basitlikte yapılıyor, bir gün işiniz düşerse bu kütüphaneyi çok seveceğinize eminim. Bu araç ile ilgili commit'e bu adresten ulaşabilirsiniz, deneme yanılma yöntemiyle geliştirdiğimden bu commit'in pek atomik bir yanı yok maalesef.

Bu hafta içerisinde canımı sıkan uzun Evernote linklerinden de projeye goo.gl link kısaltma hizmetini kullanacak eklemeler yaparak kurtuldum. Tabii ki bu özellik isteğe bağlı olacak.

Bunun haricinde hafta başında Oğuz Yarımtepe'nin uygulamayı Kde üzerinde denemesiyle projede bildirim seslerini çaldırmak için kullandığım /usr/bin/canberra-gtk-play yolunda bulunan uygulamanın sadece Gnome tabanlı masaüstü ortamlarında kurulu geldiğini öğrendim. apt-file aracıyla bu dosyanın gnome-session-canberra paketinde yer aldığını tespit ettim. Tam bu paketi bağımlılık olarak ekleme planları yapıyordum ki yine evdeki hesap çarşıya uymadı. Maalesef bu paket Gnome oturum açılış ve kapanış seslerini çaldırmakla yükümlü. Kde kullanıcılarına Gnome açılış sesi dinletmek pek akıllıca bir çözüm olmayacağından, şimdilik bu dosyayı çağıran kısımı bir try/catch bloğuna alarak hata vermesini engelledim. Tabii bu geçici bir çözüm, kalıcı çözüm için ise canberra-gtk-play kaynak kodunu incelemeye başladım. Bu C kodunun benzerini Python'a uyarlayarak bildirim seslerini libcanberra ile kendim çaldırmayı hedefliyorum.


Haftanın geri kalanında OpenSUSE Build Service ile uğraştım, daha önce kurcalayıp becerememiştim. Bu sefer oldukça olumlu sonuçlar elde ettim. Geçen hafta oluşturduğum paketleri bu kez de OBS üzerinde Ubuntu 12.04/12.10/13.04 ve Fedora 17/18 dağıtımları için hem 32 hem 64 bit olarak derletip, paketlettim. Şimdilik uygulama farklı mimarilerde derlenmeye ihtiyaç duymuyor ama önümüzdeki günlerde klavye kısayolları atamak için C ile yazılmış bir kütüphane kullanmam gerekecek (bunun nedenleriyle ilgili detaylı bir yazı yazmayı düşünüyorum) ve bu kütüphanenin her mimari için ayrı ayrı derlenmesi gerekecek. Bu açıdan OBS benim için inanılmaz işimi kolaylaştıran bir araç oldu. Ayrıca yum ve apt gibi araçlar ile de paket deposu olarak kullanılabilmesi uygulamayı kullananların güncellemeleri otomatik olarak alabilmelerini sağlayacak. Aynı işi yapan bir başka alternatif de Launchpad ancak o sadece Ubuntu dağıtımı için derleme ve paketleme işlemi gerçekleştirebiliyor. Bu açıdan OBS desteklediği onlarca dağıtım ile birkaç boy ileride diyebiliriz. 

Önümüzdeki hafta Final sınavlarım olduğu için tüm bu heyecan dolu araştırma ve geliştirme sürecine ara veriyorum. Yakından Eğitim danışmanlarına da anlayışlı davranarak bitiş tarihini on gün erteledikleri için ayrıca teşekkür etmek istiyorum.

Saygılarımla

5/11/2013

Python ile geliştirilen uygulamayı paketlemek ve dağıtmak

Geliştirdiğiniz uygulama birkaç betik dosyasından fazla ise ve çalışmak için standart Python kütüphaneleri haricinde bağımlılıklara ihtiyaç duyuyorsa artık bu uygulamayı kullanıcılara dağıtmak için paketlemenin zamanı gelmiş demektir. Ben de bu hafta EN-LinuxClipper uygulamasını paketlemekle geçirdim. Bu yazımda uygulamanın kaynak kodunu distutils ile paketleyip sonra da bunu deb veya rpm'e çevirmekten bahsedeceğim. İlerleyen günlerde Pisi Linux'un yayınlanmasının ardından bir de pisi paketi eklemeyi düşünüyorum.

Öncelikle distutils nedir?
Distutils geliştirdiğimiz Python modüllerini çeşitli sistemler arasında dağıtmak için kullanılan bir kütüphanedir. Bu iş için distutils harici kütüphaneler de vardır örneğin setuptools, distlib, distribute, distutils2 fakat bunlar içerisinde en yaygın olarak setuptools ve distutils kullanılır. Distutils2 ise yakın gelecekte Python3'e geçilmesiyle beraber varsayılan olarak kullanılacak, içerisinde distutils ve setuptools'un güzel özelliklerini barındıracak olan kütüphanedir.

setuptools yerine distutils seçmemin öncelikli nedeni deb ve rpm paketi oluşturmada sağladığı kolaylık ve daha sonraki bir yazıda detaylıca bahsedeceğim C eklentilerini kolayca derleyip bunları Python ile kullanmayı sağlaması.

5/10/2013

Tüm masaüstü ortamlarına uyumlu durum simgesi

Geçtiğimiz hafta staj görüşmesi için İstanbul'daydım, bu koşturmacanın arasında GSoC başvurusunu da ekleyince günler oldukça yoğun geçti, dönüşte de bilgisayarın adaptörü bozulunca birkaç günü de internetten sipariş ettiğim adaptörün gelmesini beklemekle geçirdim. Bu süre içerisinde çalışmaya ve blog yazmaya fırsat bulamadım fakat sonunda her şeyin yoluna girmesiyle işimin başına döndüm.

"Son adımlar hep daha çok zaman alır." sözünü bu hafta bir kez daha tekrarladım kendi kendime, eğer bir masaüstü uygulaması geliştiriyorsanız "çok" bu durumu ifade etmek için yetmeyebiliyor, çünkü Linux dünyasında her şeyden bir sürü var, bir sürü dağıtım, bir sürü masaüstü ortamı, ve bir sürü test edilecek ortam dolayısıyla bir sürü muhtemel sorun.

Bildiğiniz gibi geliştirdiğim uygulamanın simgesinin sistem çubuğunda görünmesi gerekiyor. Bununla ilgili iki temel sorunla karşılaştım.

1) Dağıtımların bu simgeleri oluşturmak için standart bir kütüphane kullanmaması.

Aslında bu tam olarak doğru değil Free Desktop'un bu konuda bir system tray standartı var ve Gtk kütüphanesindeki StatusIcon ile kullanılabiliyor fakat Canonical şirketi bunu yeterli görmemiş olacak ki libindicator isminde bir kütüphane ile birlikte hayatımıza Indicator kavramını sokmuş. Unity masaüstü ortamında Indicatorler sorunsuz görüntülenebilirken tray icon'lar için bir whitelist mekanizması uygulanıyor. Diğer masaüstü ortamlarının neredeyse hepsi sorunsuz şekilde tray icon gösteriyor eğer libindicator kuruluysa Indicatorleri de gösterebiliyorlar, fakat Ubuntu harici dağıtımlarda bu kütüphane kurulu gelmiyor. Bu durumda uygulamayı iki durumda da çalışacak şekilde değiştirmem gerekti, kodlama yönünden oldukça basit bir işti fakat bunu test etmek oldukça zahmetledi oldu. Sonunda eğer varsa libindicator yoksa sadece klasik tray icon oluşturacak şekilde çalıştırmayı başardım. Bu konuda danışmanımın bulup gösterdiği örnekler de oldukça yol gösterici oldu.

2) Her masaüstü ortamının değişik boyutlarda simge istemesi.

Eğer yolunuz /usr/share/icons içerisine düştüyse görmüşsünüzdür ki oldukça garip bir dizin hiyerarşisi var. Bir sürü simge seti ve bunlara ait bir sürü alt klasör. Bu simge setlerinden bazıları tüm dağıtımlarda standart (örneğin locolor ve hicolor) eğer uygulama geliştiricisiyseniz simgenizi bu klasörlere atmanız faydalı olacaktır. Fakat bu simge setinde de her birinin içerisinde 16x16 dan başlayarak 256x256 ya kadar değişik boyutlarda simgelerin bulunduğu alt klasörler mevcut simgeyi bir tanesine atmanız çoğu zaman sorunu çözmüyor. Bu konuda çağa uygun bir hareket yaparak svg kullandım. Bu sayede Unity'nin 22x22 simgeleri göstermesi, gnome-shell'in 64x64 simgeleri göstermesi gibi gereksiz detaylardan kurtulmuş oldum.

Eğer uygulamanız için svg simge arıyorsanız The Noun Project'e bakmanızı öneririm, içerisinde binlerce vektörel public domain simgenin bulunduğu mükemmel bir arşiv. Bu simgelerden bir tanesini seçip Inkscape üzerinde biraz oynama yaptıktan sonra uygulamaya ekledim.

Fedora ve Ubuntu üzerinde çeşitli masaüstü ortamlarında testlerimi sürdürüyorum, bu aşamada sorun kalmadığına yeterince tatmin olduktan sonra paketlemeye geçmiş olacağım ve bir sonraki yazımda da paketleme sürecinden bahsetmeyi düşünüyorum.

4/29/2013

EN-LinuxClipper ara dönem değerlendirmesi.

Birinci dönem içerisinde belirlenen 12 issue'dan 7 tanesi kapatıldı, son iki tanesi de Kullanıcı ve Geliştirici dökümanlarının hazırlanması olduğu için teknik işlerin çoğunun birinci dönemde halledildiğini söyleyebiliriz. Böyle olması güzel oldu çünkü son adımlar her zaman beklenenden çok zaman alır, hatta bu hafta da bu sorunlardan birini yaşadık.

Ara dönem raporundan önce uygulamayı tüm masaüstü ortamlarında teste sunmayı hedefliyorduk fakat uygulamanın sistem tepsisinde görünmesi gereken simgesinin bazı masaüstü ortamlarında görünmediğini farkettik, bunun temel nedeni libindicator kütüphanesinin Gnome tabanlı masaüstü ortamlarında standart olduğunu düşünmem ve uygulamayı buna göre kodlamam, fakat danışmanımın araştırmalarıyla öğrendik ki öyle değilmiş. Benzer uygulamalardan Kazam'ın kodlarını incelediğimizde eğer varsa Indicator yoksa StatusIcon kullan şeklinde bir mekanizma ile bu sorunu hallettiklerini gördük  önümüzdeki günlerde bu yöntemi uyarlayıp tüm masaüstü ortamlarında sorunsuz çalıştırmayı hedefliyoruz.

Peki uygulama neler yapabiliyor?

4/19/2013

Masaüstü uygulamaları için OAuth

Bugüne kadar OAuth'u hep web tabanlı uygulamalarda kullandığım için karşılaşmadığım bir detay bugün masaüstü uygulaması geliştirirken karşıma çıktı. Normal bir OAuth senaryosunda giriş yaptırmak istediğimiz siteye kullanıcıyı yönlendirip bir callback adresi üzerinden sitenin bize gönderdiği bilgileri alıp doğruladıktan sonra yetkilendirmeyi tamamlarız, fakat bu senaryo bir masaüstü uygulamasında yaşandığında ne yazık ki  bir callback adresimiz olmuyor. Bu durumda aklıma gelen çözümleri şu şekilde listeledim ve durumuma en uygun çözümü seçmeye çalıştım.

  • Sunucu üzerinde çalışan bir web sayfasını aracı olarak kullanmak: Bulduğum çözümler içerisinde aklıma ilk gelen ve en sağlıklı olanı buydu. tüm OAuth iletişimini "foobar.com/callback" gibi bir sunucuya yaptırıp işlem tamamlandıktan sonra gerekli token'ı alabilirdim, fakat benim geliştirdiğim uygulamanın sabit bir web sayfası olmadığından ve olur da bir gün bu sayfanın adresi değişirse uygulamayı kimse kullanamayacağından bu seçeneği elemek zorunda kaldım.
  • Callback adresi olarak "localhost:4578" gibi bir adres kullanıp bu portu dinlemek: Bu çözümün mantıklı gelmemesinin sebebi ise kullanıcının sistemiyle ilgili yeterli bilgiye sahip olmamam, kullanıcı herhangi bir güvenlik yazılımı kullanıyor mu ve bu yazılım port dinlememe izin verecek mi? ya da kaçıncı denemede ve hangi aralıkta boş bir port bulabilirim? Bu belirsizliğin yanında bir de ayrı bir thread üzerinde HTTP sunucu çalıştırma gerekliliği beni bu çözümden de uzaklaştırdı.
  • Tüm trafiği bir proxy üzerinden geçirip callback olarak belirlediğim sahte bir adresin sorgulanıp sorgulanmayacağını tespit etmek: Bu da oldukça sağlıklı gibi görünen bir çözüm olsa da bir proxy kodunu alıp projeye adapte etmek zaman olarak çok maliyetli olacaktı. (2 hafta kaybım olduğunu düşünürsek)
  • Yetkilendirme sayfasını uygulamaya gömülü WebKit ile açıp,  Proxy örneğinde olduğu gibi belirlediğim sahte bir adresi yüklemeye çalışıp çalışmayacağına bakmak: Bu örnek proxy'den sonra aklıma geldi en başta çok mantıklı görünmese de içlerinden en pratiği benim kanaatimce bu oldu. Şurada göreceğiniz gibi, callback adresi olarak http://en-linuxclipper/ verip, WebKit sayfaları açmadan önce tetiklenen olayların bir tanesinde açmak istediği benim callback adresim mi diye bakıyorum, eğer benim adresim ise oauth_verifier parametresini elde edip yetkilendirme işlemime devam ediyorum.
Bu sorunu böyle çözdükten sonra fartkettiğim ikinci detay ise ilk çözüm haricindekilerin şöyle bir eksiğinin var olması. Geliştiriciye ait keyler uygulama kodları içerisinde yer almak zorunda. Bunun ne kadar güvenlik zaafiyeti oluşturduğunu anlamak için biraz Evernote dökümanlarında gezindim, pek fikir edinemedim. Sonra Evernote ile çalışan benzer bir özgür yazılımda da bu keylerin açıkta durduğunu görünce bunun tehlikeli bir güvenlik zaafiyeti oluşturmadığını anlayıp rahat bir nefes aldım. Tabi Evernote servisi üzerinde bu keyler ile yetkilendirme harici çok bir şey yapılmaması diğer servislerde de böyle olacağı anlamına gelmiyor. Geliştirici keylerini bir özgür yazılımda açık şekilde dağıtmadan önce iyice araştırmakta fayda var.

4/18/2013

C++ Macerası neden bitti?

Projeye başlarken işin büyük kısmını kırpma aracının yani Gtk'nın oluşturacağını düşünüyordum, ortada Gtkmm kütüphanesiyle yazılmış yüzlerce örnek ve dökümanlar olunca kararı vermek kolay oldu, tabi Evernote kısmını da kontrol etmeyi ihmal etmedim görünürde onlar da API desteği veriyordu bu dil için. Fakat seçimi yapıp işe girişince bu API desteğinin sadece bir balon olduğu ortaya çıktı, ortada yazılmış bir kütüphane yoktu sadece Thrift adı verilen N farklı dilde kod çıktısı üretebilen bir araç ile üretilmiş kodlar vardı, yani aslında kimse oturup bir şeyler yazmamıştı, daha da derine inince bu kodların ne derlemesiyle ilgili ne kullanımıyla ilgili tek bir bilgi olmadığı gerçeği tekrar tekrar yüzüme çarpıyordu, projeyi bırakıp Thrift nedir onu öğrenip oradan bir şeyler çıkarmaya çalıştım bu sayede derlemeyi ve kullanmayı başardım ve bunu geliştirip bir uygulamaya dönüştürmek için C++ ile geliştirilmiş ve Evernote kullanan bir örnek aramaya koyuldum, sonuçsuz kalmadı tabii bir örnek buldum fakat kaç sürüm öncesi için yazıldığı belli olmayan bir Windows CE uygulamasıydı.

Hal böyle olunca kendimi sürekli bir çaprazlama içerisinde buluyordum benzer Thrift API'lerini kullanan ve başka servislere bağlanan uygulamalardan bir şey anlayıp, onu Java üzerinden Evernote'a bağlanan bir uygulamanın kodlarıyla karıştırıp ortaya bir şey çıkarmayı beklemek saçma oluyordu. Bana fazladan çalışmayla telafi etmem gereken iki hafta kaybettiren bu macerada;

Gtkmm'in çok stabil ve hızlı bir kütüphane olduğunu öğrendim, derleme ve döküman konusunda sıkıntı yaşatmadı, içinde Evernote veya Thrift olmayan başka bir projede mutlaka kullanmak isterim.
C++'ın Boost kütüphanesi ile sandığımdan daha pratik olabildiğini öğrendim.

Sonuç olarak projeye Python ile yeniden başladım.

Düzeltme: 2 haftalık kaybımı telafi etmek adına Python'la işlere biraz hızlı başladım, yeterince döküman ve örnek olduğu için 24 saat içerisinde ortaya çalışan bir prototip çıktı bile.


4/15/2013

Kırpma aracının ilk parçaları

Vize haftasının bitmesinin ardından projeye kaldığım yerden yoğun bir tempoyla devam ediyorum. İlk haftamı Evernote API'lerini ve bunları projeye nasıl uygulayacağımı araştırarak geçirmiştim, bu haftaki uğraşım ise projenin diğer kısmı olan kırpma aracı oldu. Öncelikle kırpma aracının görev tanımını yapmakta fayda görüyorum, kısaca bu araçtan beklenenleri şöyle listeleyebiliriz;
  • Ekran görüntüsü yakalayabilmeli
  • Ekrandaki aktif pencerenin görüntüsünü yakalayabilmeli
  • İmleç ile seçilen bir alanın görüntüsünü yakalayabilmeli
  • Pano'dan görüntü alabilmeli
  • Kısayol tuşları ile bu işlemleri daha hızlı yapabilmeli
Tüm bu görüntü yakalama işlerinde bize yardımcı olacak bileşen ise Gdk içerisinde yer alan Pixbuf, bu nesne istediğimiz boyutta resimler oluşturmak, onları bellekte tutmak, üzerinde işlem yapmak ve diske kaydetmek gibi amaçlarla kullanılıyor, aynı zamanda bir pencerenin istenilen koordinatlarından resim oluşturabilme gibi hayatı kolaylaştıran bir özelliği de var. Bu noktada karşımıza root window kavramı çıkıyor.

X pencere sisteminde, her pencere içerisinde dinamik olarak yeni pencereler oluşturulabilir, tüm bu pencereleri kapsayan pencereye ise root window denir. Masaüstü arkaplanı değiştirdiğinizde aslında yaptığınız iş bu root window'u boyamaktır, aynı şekilde masaüstündeki simgeleriniz, panelleriniz, açtığınız pencereler bu root window üzerine çizilmektedir. Yani ekran görüntüsünü almak için tek yapmamız gereken Pixbuf yardımıyla root window'dan bir imaj oluşturmak kadar basit, C++ ile yazdığım örnek koda buradan ulaşabilirsiniz.

İmleç ile bir alan seçtirmek için ise aldığımız bu ekran görüntüsünü, ekran ile aynı boyutta yeni bir pencere içerisinde açıp kullanıcının alan seçmesini sağlayacak bir arayüze ihtiyaç var, önümüzdeki günlerde bu arayüzü hazırlamayı düşünüyorum. 

Son olarak kullanıcının kısayol tuşlarıyla tüm bu işlemleri başlatabilmesi için libkeybinder kullanmayı düşünüyorum. Bir önceki projemde kullanıcı tarafından belirlenen bir tuşla pencerenin açılıp kapanması için bu kütüphaneyi kullanmıştım, fazlasıyla baş ağrıtan bir deneyim olmuştu, sonraki haftalarda bu kütüphaneyi kullanırken karşılaştığım sorunlardan ve çalışma mantığından bahsetmeyi düşünüyorum.