xscreensaver用のDropclockまたはタイプセッターとしてLinux用のスクリーンセーバーを作成

初めて見た場所を覚えていませんが、 DropClockスクリーンセーバーに魅了されました。これはすでにHabréで言及されています。



=>



しかし、ここに問題があります。作成者は、WinとMac専用にコンパイルしました。 それにもかかわらず、欲求は制限よりも強く、私は自分の実装を収集することを何としても決定しました。



最初に考えたのは、水と水しぶきのソフトウェアレンダリングを実装することです。

私の主な焦点はウェブであるため、webGLとウォーターエフェクトの実装を探し始めました。 研究の結果、彼はWebGL Waterに来ました。



私はいくつかのドキュメントを読み、helloworldsを試しましたが、これは私のものではありません。



ソースコードをざっと読んで編集しようとしただけでは、研究の主題が明確になりませんでした。 オリジナルの構成を確認することにしました。



トレントからWinバージョンをダウンロードし、ぶどうの木には行かず、仮想マシンに置きました。



実際、これはビデオが埋め込まれたフラッシュであることが判明しました。10個が黒の背景に10個、白が10個で、それぞれ1分間続きます。

swfアンパッカーはそれらをプルしませんでしたが、SWF to Video(win)コンバーターが役に立ちました。 さらに、ネイティブシステムでは、mp4 / x264 ffmpegにトランスコードされました。



さらに、問題は小さなままでした-それをブラウザで動作させるために。 変更のために、OpenWeatherMapで天気の読み込みも追加しました。



以下にマークアップを示します。



<div class="all"> <div class="d d0"><video src="dropclock_media/b0.mp4" autoplay="autoplay" loop="loop" id="d0" data-d="0"></video></div> <div class="d d1"><video src="dropclock_media/b0.mp4" autoplay="autoplay" loop="loop" id="d1" data-d="1"></video></div> <div class="d s"><div class="sep"></div></div> <div class="d d2"><video src="dropclock_media/b0.mp4" autoplay="autoplay" loop="loop" id="d2" data-d="2"></video></div> <div class="d d3"><video src="dropclock_media/b0.mp4" autoplay="autoplay" loop="loop" id="d3" data-d="3"></video></div> <div class="inspector"> <div class="time" id="info"></div> <div class="weather"></div> </div> </div>
      
      





スタイル(概要)
  html,body{height:100%;width:100%;margin:0;padding:0;overflow:hidden;} body{text-align:center;background-color:#000;color:#fff;font-family:Arial;} body.save{cursor:none;} .all{ width: 100%; max-width: 1375px; height: calc(100% - 100px); display:inline-block;white-space: nowrap;text-align:center; position: relative; padding: 0; margin:0 auto; } .d{ display:inline-block;line-height:0;/*width:312px;*/max-width:calc((100% - 115px) / 4 - 2px);height:100%; vertical-align:top;overflow:hidden;border:1px solid #000;/*background:#fff;*/ } .d:after{display:block;width:100%;height:2px;content:"";background:#000;margin-top:-2px;position:relative;z-index:100;} .s{width:115px;overflow:visible;} .d .sep{height:100%;animation: blick 1s ease infinite;} .r .sep{-webkit-animation:rotate 60s ease infinite;} .sep{position:relative;overflow:visible;} .sep:after,.sep:before{ position:absolute;top:40%;left:39%;z-index:1000;content:""; display:block;width:22%;height:20%; -webkit-animation:blick 1s ease infinite; /*background-color: red;*/ background-image: url("data:image/gif;base64,R0lGODlhAQABAIABAMzMzP///yH+EUNyZWF0ZWQgd2l0aCBHSU1QACwAAAAAAQABAAACAkQBADs="); background-repeat:no-repeat;background-size:contain; } .sep:after{margin-top:94%;} .sep:before{} video{height:100%;max-height:700px;width:calc(100% + 2px);max-width:315px;margin:-2px -1px 0;position:relative;z-index:50;} #info{/*display:none;*/text-align:right;} @-webkit-keyframes blick{ 0% {opacity:1;} 50% {opacity:.7;} 70% {opacity:.3;} 100% {opacity:1;} } @-webkit-keyframes rotate{ 0 %{-webkit-transform: rotate(0deg);} 0.2%{ -webkit-transform: rotate(-30deg); } 0.8%{ -webkit-transform: rotate(390deg); } 1%{ -webkit-transform: rotate(360deg); } 100% {-webkit-transform: rotate(360deg);} } @keyframes blick{0% {opacity:1;}50% {opacity:.7;}70% {opacity:.3;}100% {opacity:1;}} .inspector{line-height:50px;padding:0 25px;} .time{float:right;} .weather{float:left;} .weather img{vertical-align:top;} .arrow{display:inline-block;width:20px;height:50px;} @media screen and (min-height:775px){ .all{ top: calc((100% - 755px) / 2); height: calc(100% - 202px); } } @media screen and (max-height:775px){ .all{ top:25px; } }
      
      





スクリプト(jsおよび少しのjquery)
  var digits = [0,0,0,0]; var msmove = timenow(); var city = 1485357; var lastrequesttime = 0; function timenow(){ return new Date * 1; } function getRandomArbitary(min, max){return Math.random() * (max - min) + min;} function extra0(d,e){ if(e===undefined)e=1;for(var i=0; i<e; i++){if(d<Math.pow(10,(i+1))) d='0'+d;}return d;} function step(){ var now = new Date(),hors = now.getHours(),mins = now.getMinutes(),ndig = new Array(4),secs = now.getSeconds(),mili = now.getMilliseconds(); ndig[0]=Math.floor(hors/10); ndig[1]=hors-ndig[0]*10; ndig[2]=Math.floor(mins/10); ndig[3]=mins-ndig[2]*10; //ndig[4] // from last mouse move var flmm = timenow() - msmove; if(flmm > 2000) // if(!$('body').hasClass('save')) $('body').addClass('save'); // print info var info = document.getElementById('info'); info.innerHTML = // timenow()+' / '+ // msmove+' / '+ // flmm+' / '+ extra0(hors)+':'+extra0(mins)+':'+extra0(secs)+ // '.'+extra0(mili,2)+ ''; // replace for(var i in ndig){ if(ndig[i] != digits[i]){ if(lastrequesttime + getRandomArbitary(256,2048) < timenow()) updateDigit(i,ndig[i]); //document.getElementById('d'+i).src='b'+ndig[i]+'.mp4'; if(i==3){ updateWeather(); } } } setTimeout(step,getRandomArbitary(256,768)); } function updateDigit(i,n){ var d = $('#d'+i).clone().attr('src','dropclock_media/b'+n+'.mp4').appendTo('.d'+i); //setTimeout(function(){ // var i = d[0].dataset.d; $('#d'+i+':first').remove(); // },15000); //document.getElementById('d'+i).src='b'+n+'.mp4'; lastrequesttime = timenow(); digits[i] = n; } function updateWeather(){ // weather $.getJSON('http://api.openweathermap.org/data/2.5/weather?id='+city,function(data){ console.dir(data); var icon = 'http://openweathermap.org/img/w/'+data.weather[0].icon+'.png', temp = Math.floor(data.main.temp - 273.15), arrst= 'transform: rotate('+data.wind.deg+'deg);-webkit-transform: rotate('+data.wind.deg+'deg);', w_html = // ':'+ data.name+' '+ data.sys.country+' '+ '<img src="'+icon+'">'+ data.weather[0].main+', '+ data.weather[0].description+' '+ ((temp>0)?'+':'')+temp+'° '+ '; Wind '+data.wind.speed+'m/s <div class="arrow" style="'+arrst+'">↓</div>'+ ''; $('.weather').html(w_html); }); } $(function(){ // timer step(); $(window).mousemove(function(){ if(document.body.classList.contains('save')) document.body.classList.remove('save'); msmove = timenow(); }); });
      
      









firefoxでは、ビデオの速度が遅くなり、ガタガタと音がするので、最初はwebkitに集中しました。

数値が一度に消えないように、数値の立ち下がりに遅延を追加しました。

うまく機能しているようですが、スタンドアロンファイルとして実行する必要があります。



私はubuntaでwebbrowser-appシステムミニブラウザを見つけ、そのパラメータを掘り下げて、このランチャーを次のように書きました:



 #/bin/sh webbrowser-app --chromeless --fullscreen /var/www/vhosts/localhost/dropclock/index.html
      
      





しかし、xscreensaverは彼に多くのことを誓い、私は何か間違ったことをしていることに気づきました...



時間が経つにつれて、美しいスクリーンセーバーを手に入れたいという欲求はまったく満たされなくなりました。 9月13日、全ロシアのプログラマーの日、仕事は中断され、再び幽霊のような目標を達成することに注意が向けられました。 その前に、私はPythonでウィンドウアプリケーションを目にしましたが、選択は彼にかかったのです。 以前に何も書いたことはありません。 私は基本的な例を分析し始め、ウェブキットを追加しました。

やった! 稼いだ!
 #!/usr/bin/env python # -*- coding: utf-8 -*- import pygtk pygtk.require('2.0') import os, argparse, gtk, webkit from gtk import gdk class DropClock: def createParser(): self.parser = argparse.ArgumentParser() self.parser.add_argument ('-r', '--root', action='store_const', const=True, default=False) self.namespace = self.parser.parse_args() def delete_event(self, widget, event, data=None): print "  " return False def destroy(self, widget, data=None): print "  " gtk.main_quit() def __init__(self): self.parser = argparse.ArgumentParser() self.parser.add_argument ('-r', '--root', action='store_const', const=True, default=False) self.parser.add_argument ('-w', '-window-id', action='store_const', const=True, default='') self.namespace = self.parser.parse_args() url = 'file://' + os.path.realpath('./index.html') self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.set_default_size(1600, 768) self.window.set_position(gtk.WIN_POS_CENTER) self.window.connect("delete_event", self.delete_event) self.window.connect("destroy", self.destroy) self.browser = webkit.WebView() self.browser.props.settings.props.enable_default_context_menu = False self.browser.load_uri(url) self.window.add(self.browser) self.window.show_all() # if self.namespace.root: # self.window.fullscreen(); def main(self): gtk.main() # self.createParser(); if __name__ == "__main__": hello = DropClock() hello.main()
      
      







xscreensaverに固定できる場合はどうなりますか? Pythonのスクリーンセーバーの例が見つかりましたが、それに基づいて独自のスクリーンセーバーが作成されました。

超自然的ではない
 #!/usr/bin/python import os import sys import gtk, webkit from gtk import gdk # the secret sauce is to get the "window id" out of $XSCREENSAVER_WINDOW # code comes from these two places: # 1) http://pastebin.com/nSCiq1P3 # 2) http://stackoverflow.com/questions/4598581/python-clutter-set-display class ScreenSaverWindow(gtk.Window): def __init__(self): gtk.Window.__init__(self) pass def delete_event(self, widget, event, data=None): return False def destroy(self, widget, data=None): gtk.main_quit() def realize(self): if self.flags() & gtk.REALIZED: return ident = os.environ.get('XSCREENSAVER_WINDOW') if not ident is None: print 'if not ident is None:' self.window = gtk.gdk.window_foreign_new(int(ident, 16)) self.window.set_events (gdk.EXPOSURE_MASK | gdk.STRUCTURE_MASK) # added by aja x, y, w, h, depth = self.window.get_geometry() # self.size_allocate(gtk.gdk.Rectangle(x, y, w, h)) self.set_default_size(w, h) self.move(x, y) self.set_decorated(False) # aja - more self.window.set_user_data(self) self.style.attach(self.window) self.set_flags(self.flags() | gtk.REALIZED) #self.window.connect("destroy", self.destroy) if self.window == None: print 'self.window == None:' self.window = gdk.Window(None, 1024, 768, gdk.WINDOW_TOPLEVEL,(gdk.EXPOSURE_MASK | gdk.STRUCTURE_MASK),gdk.INPUT_OUTPUT) # self.window.set_title("DropClock") if self.window != None: print 'self.window != None:' #self.window.add_filter(lambda *args: self.filter_event(args)) self.set_flags(self.flags() | gtk.REALIZED) self.browser = webkit.WebView() url = 'file://' + os.path.join(os.path.dirname(__file__) + '/index.html') self.browser.load_uri(url) self.add(self.browser) self.browser.show() window = ScreenSaverWindow() window.set_title('DropClock') window.connect('delete-event', gtk.main_quit) window.set_default_size(1024, 768) window.realize() window.modify_bg(gtk.STATE_NORMAL, gdk.color_parse("black")) window.show() gtk.main()
      
      





〜/ .xscreensaverでは、リストの下に行が追加されます。

- "Drop Clock" /var/www/vhosts/localhost/dropclock/dropclock_xss.py \n\





その後、小さなウィンドウで正しく表示するためのスタイルの適応性はまだ解決されていましたが、うまくいきました、私はそれが好きです。



プログラマーの日は成功したと推測できます。



ビデオはマグネットリンクにあります。



UPD:ビデオを少し振りました 一部の解像度とデモでは、ビデオの上部と下部に白いバーが表示されました

UPD:自分自身を収集するのが面倒な人のために、交換機へのリンク



All Articles