data = array(); if($file == null) $this->file = $this->get_default_file(); else $this->file = $file; $this->set_defaults($defaults); $this->load(); $this->changed = false; $this->auto_save = true; } public function __destruct(){ if($this->changed){ $this->save(); } } public function __get($name){ return $this->data[$name]; } public function __set($name, $value){ # echo "Config::set($name=$value)\n"; if(isset($this->data[$name])){ if($this->data[$name] != $value){ $this->data[$name] = $value; $this->changed = true; } } else{ $this->data[$name] = $value; $this->changed = true; } } public function __isset($name){ return isset($this->data[$name]); } public function __unset($name){ unset($this->data[$name]); } public function keys(){ return array_keys($this->data); } public function save(){ $bool = file_put_contents($this->file(), serialize($this->data)); if($bool === false) throw new Exception('error writing file ' . $this->file()); $this->changed = false; return $bool; } public function load(){ if(file_exists($this->file())){ $this->data = unserialize(file_get_contents($this->file())); return true; } return false; } protected function get_default_file(){ return basename(__FILE__, '.php') . '.ini' ; } protected function set_defaults($defaults){ $this->data = $defaults; } protected function file(){ return $this->file; } } class Frame extends GtkEventBox{ protected $container; public function __construct($border_color='#aaa', $background='#EEE', $border_width=1){ parent::__construct(); $this->set_border_width(0); $this->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse($border_color)); $this->container = new GtkEventBox(); parent::add($this->container); $this->container->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse($background)); $this->container->set_border_width($border_width); } public function add($w){ $this->container->add($w); } } class Button extends GtkEventBox{ protected $label; protected $callbacks; public function __construct($label){ parent::__construct(); $this->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse('#EEE')); $frame = new Frame(); $this->add($frame); $frame->add($this->label = new GtkLabel($label)); $this->label->modify_font(new PangoFontDescription('Sans Bold 6')); $this->add_events(Gdk::BUTTON_PRESS_MASK); $this->connect('button-press-event', array($this, 'button_press_event')); # $this->connect('motion-notify-event', array($this, 'motion_notify_event')); $this->callbacks = array(); $this->set_border_width(0); } public function connect($signal, $callback){ if($signal == 'clicked'){ $this->callbacks[] = $callback; } else parent::connect($signal, $callback); } public function motion_notify_event($w, $event){ return true; } public function button_press_event($selft, $event){ foreach($this->callbacks as $callback){ call_user_func($callback, $event); } return true; } } class MovableWidget extends GtkEventBox{ protected $clic_point; protected $config; public function __construct($config=null){ parent::__construct(); $this->add_events(Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK); $this->connect('motion-notify-event', array($this, 'motion_notify_event')); $this->connect('button-press-event', array($this, 'button_press_event')); $this->connect_simple('realize', array($this, 'on_realize')); $this->click_point = null; if($config == null) $this->config = new Config(); else $this->config = $config; $this->set_border_width(0); } public function on_realize(){ if(isset($this->config->x)){ $this->get_window()->move($this->config->x, $this->config->y); } } public function button_press_event($w, $event){ $this->click_point = array( 'x_root' => $event->x_root, 'y_root' => $event->y_root ); } # move window location following mouse. public function motion_notify_event($w, $event){ $state = $event->state & ~(Gdk::BUTTON_MOTION_MASK); # no button press if($state == 0) return; $win = $this->get_window(); $pos = $win->get_position(); $x = $pos[0] + $event->x_root - $this->click_point['x_root']; $y = $pos[1] + $event->y_root - $this->click_point['y_root']; $win->move($x, $y); $this->config->x = $x; $this->config->y = $y; $this->click_point = array( 'x_root' => $event->x_root, 'y_root' => $event->y_root ); } public function get_window(){ $parent = $this; do{ $w = $parent; $parent = $w->get_parent(); } while($parent != null); return $w; } } class ClockWidget extends GtkLabel{ protected $timeout_id; protected $format; public function __construct($format = 'd/m - H:i:s'){ parent::__construct(); $this->format=$format; $this->timeout_id = Gtk::timeout_add(1000, array($this, 'on_timeout')); $this->modify_font(new PangoFontDescription('Sans 7')); $this->on_timeout(); } public function on_timeout(){ $this->set_text(date($this->format)); return true; } } class TitleBar extends MovableWidget{ protected $hbox; public function __construct($config, $title){ parent::__construct($config); $this->hbox = new GtkHbox(); $this->hbox->pack_start($this->label = new GtkLabel($title)); $this->label->modify_font(new PangoFontDescription('Sans Bold 7')); $this->hbox->pack_end($this->button_close = new Button(' x '), false, false); $this->hbox->pack_end($this->button_minimize = new Button(' ^ '), false, false); $this->hbox->pack_end($this->button_reduce = new Button(' - '), false, false); $this->button_close->connect('clicked', array($this, 'on_button_close')); $this->button_minimize->connect('clicked', array($this, 'on_button_minimize')); $this->button_reduce->connect('clicked', array($this, 'on_button_reduce')); $this->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse('#aaa')); $this->add($this->hbox); $this->show_all(); } public function on_button_close(){ Gtk::main_quit(); } public function on_button_minimize(){ $this->get_window()->hide_all(); } public function on_button_reduce(){ static $visible = true; $w = $this->allocation->width; if($visible){ $this->managed_widget->hide_all(); $h = $this->allocation->height; } else{ $this->managed_widget->show_all(); $h = $this->allocation->height +$this->managed_widget->allocation->height; } $visible = !$visible; $this->get_window()->resize($w, $h); } public function manage($widget){ $this->managed_widget = $widget; } } class DesktopGadget{ protected $config; protected $pannel; protected $title_bar; protected $window; function __construct($title, $type=1){ $this->config = new Config(); switch($type){ case 1: $this->window = new GtkWindow(Gtk::WINDOW_POPUP); # display over any window break; case 2: $this->window = new GtkWindow(); $this->window->set_type_hint(Gdk::WINDOW_TYPE_HINT_DOCK); # display over any window, below gtk panel break; case 3: $this->window = new GtkWindow(); $this->window->set_type_hint(Gdk::WINDOW_TYPE_HINT_DESKTOP); # display on gtk desktop, under any window break; case 4: # raw toplevel + some attributes ; won't move over panel or outside screen $this->window = new GtkWindow(); $this->window->set_skip_taskbar_hint(true); $this->window->set_skip_pager_hint(true); $this->window->set_keep_above(true); # $this->window->set_keep_below(true); $this->window->stick(); $this->window->set_decorated(false); break; case 'parameters-to-try': # http://gtk.php.net/manual/en/gdk.enum.windowtypehint.php $this->window->set_skip_taskbar_hint(true); $this->window->set_skip_pager_hint(true); $this->window->set_keep_above(true); $this->window->set_keep_below(true); $this->window->stick(); $this->window->unstick(); $this->window->set_decorated(false); break; default: throw new Exception ("un supported DesktopGadget type '$type'"); } $frame = new Frame('darkgreen'); $vbox = new GtkVbox(); $frame->add($vbox); $this->title_bar = new TitleBar($this->config, $title); $vbox->pack_start($this->title_bar, false, false); $this->panel = new GtkVbox(); $vbox->pack_end($this->panel, true, true); $this->title_bar->manage($this->panel); # settings # $this->window->set_size_request( 100, -1 ); # set window size # place window to screen center ; will be overriden at realize with saved (x,y) from config $this->window->set_position(Gtk::WIN_POS_CENTER); # connection tree $this->window->add($frame); # terminate $this->window->show_all(); } # override composite methods : add, pack_start, pack_end; # now add child widget to $this->pannel (a GtkVbox widget) public function add($w){ $this->pack_start($w); } public function pack_start($w, $expand = true, $fill = true, $padding=0){ $this->panel->pack_start($w, $expand, $fill, $padding); $this->window->show_all(); } public function pack_end($w, $expand = true, $fill = true, $padding=0){ $this->panel->pack_end($w, $expand, $fill, $padding); $this->window->show_all(); } } $gadget = new DesktopGadget($title='Desktop Gadget'); $gadget->pack_start($clock = new ClockWidget()); Gtk::main(); ?>