1. PHP on the Web and Desktop
Webservices and PHP-GTK
2. Whoami
• http://elizabethmariesmith.com
• Work at http://omniti.com
• PHP-GTK
• PECL cairo
• WinGui
• Bad bad bad things to PHP (on windows)
• Twitter @auroraeosrose
• IRC auroraeosrose
3. Community Heckling
• On twitter #zendcon
• Bonus points if you start tweeting with the app
• IRC is open, I can see backlog – constructive
criticism is good
• Comment on http://joind.in/talk/view/952
• No comments on hair, clothes, or my fat belly –
constructive criticism is welcome ;)
4. The Desktop Is Dead?
• If the desktop is dead… what is this browser
thing you use everyday?
• What is really happening?
• RIA? WTF is RIA?
5. RIA
Rich Internet Applications
web applications that have most of the
characteristics of desktop
applications, typically delivered by
way of standards based web browser
plug-ins or independently via
sandboxes or virtual machines
(wikipedia)
6. Webservices
• API’s you can talk to using HTTP
• Extend the power of the web
anywhere and everywhere
7. PHP
• Ability to talk HTTP natively
(streams) or with several
extensions (pecl_http and curl)
• Lots of code already written for
common problems involving web
8. PHP-GTK
• Cross platform widget toolkit for
desktop programs
• Native look and feel for all
platforms – this includes Windows
and Mac
• Reuse all the code you already
have for your models
9. Why the desktop?
• People aren’t always online
• Some things would be bandwidth prohibitive
• Some data is too sensitive
• Embedded OSs have issues
• Browsers are just Quirky
• Current Desktop RIA tools are still young
10. Why use PHP
• No new language to learn
• No Compiling
• Instant Changes
• Plug into PHP extensions
• Easy to Use
• Fast to Write
• Use existing code
11. Disadvantages
• Slower than compiled code
• Distribution of runtime
– New installers help with that
• Distribution of code
– Phar helps with that
• Code “protection”
– Can use encoders but anyone with
enough effort could decode
12. What is PHP-GTK
• Language bindings for GTK+
– Cross platform widgeting toolkit, if you use gnome
you use it
• Multiple “backends” – speaks Windows, Mac
OSX and X server
• Needs php CLI, php-gtk extension, and gtk
libraries to run
14. Some points to remember
1. In CLI applications, memory is more
important than speed
2. Clean up after yourself, unset is your
friend
3. The OS is handling theming. Unlike
html, where the design is controlled by
you. If you manipulate themes, users
WILL be irritated.
15. Some points to remember
4. Do not connect directly to a database
on another machine. This is asking for
security issues. Instead slap a
webservice in front of the database for
your app.
5. Use 5.3 The memory savings you’ll get
will make it worth the hassle of having
a special CLI binary just for PHP-GTK
16. GTK Theory
• Twitter is the new “Hello World”
• Use pre-existing twitter API class for talking to
twitter via PHP streams
• See how much work we saved? We just write
the pretty front-end
17. Widgets
• A building block for GUIs
– Window
– Button
– Menu
• "True" widgets descend from GtkWidget
• Some widgets have their own window
• Some widgets draw on the window
beneath them instead
18. Containers
• Specialized widget, holds other widgets
• Can nest containers inside containers
• GTK+ does not do pixel perfect or fixed
positioning, instead it uses packing
• Packing defines the size of the widgets
19. Signals
• Event driven, not line by line
• Emits "signals" that have a default
handler and can have other callbacks
attached
• Different widgets can have the same
signal with a different meaning
20. Main Loop
• No code will run after calling Gtk::main()
until you call Gtk::main_quit()
• The loop sits around until something
happens that emits a signal or event
• Long running script as opposed to quick
set up and tear down
21. On to Code
• http://gtk.php.net
• http://elizabethmariesmith.com/slides
22. A note on settings
• Store settings in user defined location
• Xml or ini files are good formats, can also use
sqlite for lots of settings
• Limited by user permissions for reading and
writing
23. Windows – the GTK kind
• Usually you have one main
window
• You can create pretty splash
screens if desired
• Windows can be grouped, and can
be either a parent or transient for
another window
25. Create our Main Window
• If we close it, the program ends
• Can set pretty icons for the corner
and stuff a single widget inside
• You can’t see any widgets until you
show them
26. <?php
class Php_Gtk_Twitter_Client extends GtkWindow {
public function __construct() {
parent::__construct();
$this->set_icon($this->render_icon(
Gtk::STOCK_ABOUT, Gtk::ICON_SIZE_DIALOG));
$this->set_size_request(300, 500);
$this->set_title('PHP-GTK Twitter Client');
$this->connect_simple('destroy', array('Gtk', 'main_quit'));
}
}
$window = new Php_Gtk_Twitter_Client;
$window->show_all();
Gtk::main();
27. A word on Glade/Gtkbuilder
• Design your layouts in an editor
(glade3)
• Save them as xml files
• Load them via special methods in
PHP-GTK
• Automatically generated widgets
28. Specialty Widgets and Events
• Events are lower level things that happen
• You can attach to events like you attach to
signals
• Lots of specialty widgets to do fancy stuff, from
infobars to aboutdialogs to statusicons – and
that’s not counting extensions
29. Minimize to the Tray
• Attach to the minimize event (this
is not as easy as it looks)
• Attach to the activate event
• Make them act differently then
they normally would
30. <?php
public function activate_window($icon, $window) {
if ($window->is_visible()) {
$window->hide();
} else {
$window->deiconify();
$window->show();
}
}
$this->statusicon->connect('activate', array($this->statusicon,
'activate_window'), $this);
$this->set_skip_taskbar_hint(true);
$this->connect('window-state-event', array($this, 'minimize_to_tray'));
public function minimize_to_tray($window, $event) {
if ($event-
>changed_mask == Gdk::WINDOW_STATE_ICONIFIED &&
$event-
>new_window_state & Gdk::WINDOW_STATE_ICONIFIED) {
$window->hide();
}
return true; //stop bubbling
}
31. • I really don’t believe in wheel inventing , especially when I have little
experience with the subject. However there is an issue – every existing
twitter API uses curl – and I don’t want to depend on an extension that
isn’t always installed
protected function process($url, $date = 0, $type = 'GET', $data = null) {
// add caching header
$this->headers[0] = 'If-Modified-Since: ' . date(DATE_RFC822, $date);
$options = array(
'http' => array(
'method' => $type,
'header' => $this->headers)
);
if (!is_null($data)) {
$options['http']['content'] = http_build_query($data);
}
$context = stream_context_create($options);
if ($this->username && $this->password) {
$base = 'http://' . urlencode($this->username) . ':' . urlencode($this->password)
. '@twitter.com/';
} else {
$base = 'http://twitter.com/';
}
set_error_handler(array($this,'swallow_error'));
$string = file_get_contents($base . $url, false, $context);
restore_error_handler();
return json_decode($string);
}
32. TreeView Madness
• You will use lots of treeviews
• Treeviews work with two
components, a view and model
• TextViews work in a similar
manner
• TreeViews have columns with
renderers
33. $store = new GtkListStore(GdkPixbuf::gtype, Gobject::TYPE_STRING,
Gobject::TYPE_STRING, Gobject::TYPE_LONG, GObject::TYPE_STRING,
GObject::TYPE_BOOLEAN, GObject::TYPE_STRING, Gobject::TYPE_LONG);
$store->set_sort_column_id(7, Gtk::SORT_DESCENDING);
$list = $this->twitter->get_public_timeline();
// stuff the store
foreach($list as $object) {
$store->append(array(null, $object->user->profile_image_url, $object->user->name,
$object->user->id, $object->text, $object->favorited, $object->created_at,
$object->id));
}
$this->treeview = new GtkTreeView($store);
$picture_renderer = new GtkCellRendererPixbuf();
$picture_column = new GtkTreeViewColumn('Picture', $picture_renderer, 'pixbuf', 0);
$picture_column->set_cell_data_func($picture_renderer, array($this, 'show_user'));
$this->treeview->append_column($picture_column);
$message_renderer = new GtkCellRendererText();
$message_renderer->set_property('wrap-mode', Gtk::WRAP_WORD);
$message_renderer->set_property('wrap-width', 200);
$message_renderer->set_property('width', 10);
$message_column = new GtkTreeViewColumn('Message', $message_renderer);
$message_column->set_cell_data_func($message_renderer,
array($this, 'message_markup'));
$this->treeview->append_column($message_column);
$this->treeview->set_resize_mode(Gtk::RESIZE_IMMEDIATE);
36. Packing Fun
• GTK is not “pixel perfect”
• Packing is not as hard as it looks
• Containers can hold one or many
• Remember that a container
expands to the size of it’s contents
38. Dialogs
• Dialogs are cool
• Dialogs are usually modal, but not
always
• Dialogs can be very general or
very specific
• You can put anything inside one
39. class Php_Gtk_Twitter_Login_Dialog extends GtkDialog {
protected $emailentry;
protected $passwordentry;
public function __construct($parent) {
parent::__construct('Login to Twitter', $parent, Gtk::DIALOG_MODAL,
array(
Gtk::STOCK_OK, Gtk::RESPONSE_OK,
Gtk::STOCK_CANCEL, Gtk::RESPONSE_CANCEL));
$table = new GtkTable();
$email = new GtkLabel('Email:');
$table->attach($email, 0, 1, 0, 1);
$password = new GtkLabel('Password:');
$table->attach($password, 0, 1, 1, 2);
$this->emailentry = new GtkEntry();
$table->attach($this->emailentry, 1, 2, 0, 1);
$this->passwordentry = new GtkEntry();
$table->attach($this->passwordentry, 1, 2, 1, 2);
$this->passwordentry->set_visibility(false);
$this->vbox->add($table);
$this->errorlabel = new GtkLabel();
$this->vbox->add($this->errorlabel);
$this->show_all();
}
public function check_login($twitter) {
$this->errorlabel->set_text('');
$email = $this->emailentry->get_text();
$password = $this->passwordentry->get_text();
if (empty($password) || empty($password)) {
$this->errorlabel->set_markup(
'<span color="red">Name and Password must be entered</span>');
return false;
}
if ($twitter->login($email, $password)) {
return true;
} else {
$this->errorlabel->set_markup(
'<span color="red">Authentication Error</span>');
return false;
}
}
}
41. Entering Data
• GTKEntry
• Basic Data Entry – activates on
return, can set maximum length
allowed
• Simple label for messages – could
use a dialog or other method of
informing the user
42. // Create an update area
$this->updateentry = new GtkEntry();
$this->updateentry->set_max_length(140);
$this->updateentry->set_sensitive(false);
$this->updateentry->connect('activate',
array($this, 'send_update'));
$this->entrystatus = new GtkLabel();
public function send_update($entry) {
if ($this->twitter->send($entry->get_text())) {
$this->entrystatus->set_text('Message Sent');
$this->update_timeline();
$this->updateentry->set_text('');
} else {
$this->entrystatus->
set_markup(‘<span color="red">Error Sending Message - Try Again</span>');
}
}
How many people have ever heard “the desktop is dead, everything is online”There have been several recent articles about itEveryone is touting their RIA application that “works like a desktop”If the desktop is dead, and everything is going to be online, why do you keep hearing about this RIA thing?
So what they’re really saying is – web apps that want to act like desktop appsEverybody wants the connection of the internet, but the user experience of a desktop applicationSo how do we join the two?
Name a webservice you use all the time ( I better hear twitter)Can use straight REST, SOAP, xml-rpc (ugh), plus other variants
So how do we take these three things – an application that wants to be on the desktop, not just the web, webservices we hit with http, and PHP which “talks http” fabulously?
Contrary to popular belief, people still work offlineEmbedded OS’s have major issues with memory and bandwidth and websites not working properly with themWho here has had issues with IE ever?And then there’s issues with AIR or silverlight or titanium… they just don’t quite work yet
There are lots of advantages to using PHP to write a desktop app
Speed is the big reason to pick C or something similar – stacked against ruby or python though, that’s the only advantage ;)The code protection, runtime distribution, etc only let’s you win over C or similar languages, not against python or ruby or other $flavor of the dayNote that runtime distribution is going to differ from platform to platformIt’s 13MB for EVERYTHING for windows – php, php-gtk, all the gtk libraries even esoteric stuff, and one or two localizationsMac has a new runtime that doesn’t require X – which is awesome
GTK was Gimp Tool Kit (long long ago)Php-gtk is really php-gtk2 – but php-gtk1 only works on php4 which is dead, so it in esscense is dead as well (good riddance)Your computer does not care about HTML.Your shell does not care about HTML.PHP does not care about HTML.Because of all of this, you should not care about HTML.PHP and GTK does not use HTML.PHP and GTK does not build web pages.PHP and GTK does not build web applications.PHP and GTK builds computer programs.- From bob MajdakThere are other options, but right now none work as well or are as complete as php-gtkPHP-QTWxWidgetsWin\\GuiWinbinder
Do not change the users desired colors and theme unless absolutely necessary and make sure there are ways for the use rto control the changes the OS is handling theming for a reasonYou can’tbe certain users have the sametheme as you, gtkcan have anynumber of themes and look manydifferentwaysThere ishowever, nothingwrongwithofferingusers options – perhaps an option to makeiteasier to use on embeddeddevices, withfingerwidthscrollbars and otherusefultools
It’s trivial to add a webservice for your database, and much safer then allowing access across the network to the dbRemember you can do multiple CLI binaries on a system – one just for php-gtk is fine
We already have a class to manage caching data in an sqlite3 DB via PDO, and a class to manage talking to the Twitter API – reusing code is greatYou can use any PHP code with php-gtk – from Zend Framework to anything else you want
Widgets – think legos, each with a specific shape and specific jobThere are a LOT of gtk widgets, and some “widgets” that aren’t widgets…Brief note about two types of windows – a gtkwindow (the actual widget window) and gdkwindow (what the widget is drawing in)
The contained widgets are container's children.Containers usually respond to resize events and addition and removal of children by reallocating the available space among its remaining children.
In computer programming, event-driven programming or event-based programming is a programming paradigm in which the flow of the program is determined by events—i.e., sensor outputs or user actions (mouse clicks, key presses) or messages from other programs or threads.Signals are identified by nameMention “events’ as well and bubbling and signal emission order
Different style of programming
TODO: get the installers done and in place, linux installer of bobs
Encrypting settings isn’t going to gain you much, although you can do it if you are really paranoidWhere is the “user defined location”APPDATA for windows and HOME for most other systems (in $_SERVER)There are also some other “special location” – on windows you can get to these through some com tricks
These are the window widgets – there are also gdk windows – those are the areas where the underlying system actually draws onto – they’re both called windows just to confuse the hell out of you
Creating a splash screen means creating a window, hinting it as a splashscreen, telling it not to have edges or taskbar or resize, then taking an image and rendering it as the background – the mask stuff means that it can be a transparent png or the like and have a custom shape
Stuff to know
Using what we just talked aboutLet’s start with a basicgtk window – notice it’s easier to extend the base classConnect the destruction of our main window with stopping theConcepts – signals and connections, the main loop and main_quit, show allNotice if you put PHP after the main(); call it will not be executed until after the main_quit call
Gtkbuilder is preferred, and it’s built in – glade is old and busted – but the editor (glade3) is the same for both, just change the output you want
There are more than 50 widgets, and those widgets have thousands of signals and methods…GTK is HUGE and learning the cool stuff available might take awhile (remember when you started learning PHP?)
The full code shows how to create the status icon and other fun stuff
My own simple twitter class – login, logout, public timeline, own friends timeline, send message Concepts – use PHP code with PHP-GTK, can use other extensions but then they have to be installed
So to show something in a treeview, you create a datastore, stuff in the data, then create a treeview, hook it to the model – then create renderers for each type of data you want to show, put the renderer(s) in a column, and put the column in a treeview (deep breath)
So to show something in a treeview, you create a datastore, stuff in the data, then create a treeview, hook it to the model – then create renderers for each type of data you want to show, put the renderer(s) in a column, and put the column in a treeview (deep breath)
First version of the app with the public timeline
So to show something in a treeview, you create a datastore, stuff in the data, then create a treeview, hook it to the model – then create renderers for each type of data you want to show, put the renderer(s) in a column, and put the column in a treeview (deep breath)
Concepts: packing and toolbarsMore gtktimeout
General concept of dialogs – when is a good time for modal dialogs, when is not a good time
Concepts: packing and toolbarsMore gtktimeout
Concepts: packing and toolbarsMore gtktimeout
Add data in with a gtkentry
Concepts: packing and toolbarsMore gtktimeout
Here’s the finished app – then I’ll run it in action