# Πίνακας μηνύματος (C)

Ένα απλό πρόγραμμα που χρησιμοποιεί WebKitGTK+ και DOM.
Shaun McCance
shaunm@gnome.org 2010
Marta Maria Casetti
mmcasetti@gmail.com 2013
Ελληνική μεταφραστική ομάδα GNOME
team@gnome.gr 2012-2015
Δημήτρης Σπίγγος
dmtrs32@gmail.com 2012, 2013
Μαρία Θουκιδίδου
marablack3@gmail.com 2014
Θάνος Τρυφωνίδης
tomtryf@gmail.com 2014, 2015

# Πίνακας μηνύματος

      Σε αυτό το μάθημα, θα μάθετε:

        Πώς να εμφανίσετε μια ιστοσελίδα με WebKit.
        Πώς να χειριστείτε τα περιεχόμενα μιας ιστοσελίδας χρησιμοποιώντας τις συναρτήσεις DOM του WebKit.

      Αυτό το μάθημα υποθέτει εξοικείωση με τη γλώσσα προγραμματισμού C και βασική κατανόηση της GTK+, συμπεριλαμβανόμενης της δημιουργίας και τοποθέτησης γραφικών στοιχείων και της σύνδεσης συναρτήσεων επανάκλησης σε σήματα. Δείτε  για να μάθετε τα βασικά του GTK+.

# Δημιουργία έργου με το Anjuta

Το GNOME περιέχει το WebKitGTK+, κατασκευασμένο πάνω στον ισχυρό σκελετό του WebKit HTML. Το WebKit χρησιμοποιείται μέσα από το GNOME, όχι μόνο για προβολή ιστοσελίδων στο διαδίκτυο, αλλά επίσης για δημιουργία πλούσιων διεπαφών χρήστη που μπορούν εύκολα να μορφοποιηθούν με CSS.

Σε αυτό το μάθημα, θα δημιουργήσετε ένα απλό πίνακα μηνύματος χρησιμοποιώντας WebKit. Ο πίνακας μηνύματος θα επιτρέψει την εισαγωγή κάποιου κειμένου και την προσθήκη του σε μια λίστα μηνυμάτων σε HTML. Πριν την εκκίνηση, χρειαζόσαστε να ρυθμίσετε ένα έργο στο Anjuta.

Στο Anjuta, κάντε κλικ στο Αρχείο Νέο Έργο για να ανοίξετε τον νέο βοηθό έργου.

Επιλέξτε GTK+ (απλό) στην καρτέλα C και κλικ συνέχεια.

Συμπληρώστε τις λεπτομέρειές σας στη σελίδα βασικές πληροφορίες. Χρησιμοποιήστε πίνακα μηνύματος για το όνομα του έργου. Κλικ συνέχεια.

Απενεργοποιήστε την επιλογή χρήση GtkBuilder για διεπαφή χρήστη καθώς αυτό το μάθημα κατασκευάζει τη διεπαφή χρήστη χειροκίνητα.

Πρέπει να πείτε στο Anjuta ότι χρησιμοποιείτε WebKitGTK+ για αυτό το έργο. Στη σελίδα επιλογές έργου, επιλέξτε ρύθμιση εξωτερικών πακέτων. Κλικ συνέχεια. Στη σελίδα ρύθμιση εξωτερικών πακέτων, σημειώστε webkitgtk-3.0.

Αφού τελειώσετε με τον βοηθό του νέου έργου, ανοίξτε το αρχείο src/main.c είτε από το έργο ή από την καρτέλα αρχείο. Το Anjuta θα το γεμίσει με κάποιο βασικό κώδικα GTK+ από τα πρότυπά του. Αφού δημιουργείτε ένα έργο WebKit, χρειάζεστε πρώτα να συμπεριλάβετε τις κεφαλίδες WebKit. Μετά τη γραμμή που περιέχει `gtk/gtk.h`, προσθέστε την παρακάτω γραμμή:

#include <webkit/webkit.h>

Επιβεβαιώστε ότι όλα δουλεύουν με την κατασκευή που έχετε κάνει μέχρι τώρα. Κλικ κατασκευή έργο κατασκευής ή απλά πατήστε Shift F7. Την πρώτη φορά που κατασκευάζετε, θα σας ζητηθεί για κάποιες επιλογές ρύθμισης. Απλά αποδεχτείτε τις προεπιλογές και κλικ εκτέλεση.

Τώρα θα μπορείτε να τρέξετε το πρόγραμμα. Κάντε κλικ στο Τρέξιμο Εκτέλεση ή απλά πατήστε F3. Θα πρέπει να δείτε ένα άδειο παράθυρο.

# Διευθέτηση του παραθύρου σας και προβολή ιστού

Τώρα που μπορείτε να δείτε ένα παράθυρο, είναι καιρός να ξεκινήσετε δουλειά με το WebKit. Για αυτό το μάθημα, θα δημιουργηθεί μια καταχώριση κειμένου και μια προβολή ιστού και πακετάρισμα τους σε ένα παράθυρο. Βρείτε τη συνάρτηση `create_window` και αντικαταστήστε την με την παρακάτω:

static GtkWidget* create_window (void) { GtkWidget *window, *box, *scroll, *view, *entry;

window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size (GTK_WINDOW (window), 400, 400); gtk_window_set_title (GTK_WINDOW (window), "Message Board"); g_signal_connect (window, "delete-event", G_CALLBACK (gtk_main_quit), NULL);

box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_container_set_border_width (GTK_CONTAINER (box), 6); gtk_container_add (GTK_CONTAINER (window), box);

entry = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (box), entry, FALSE, FALSE, 0);

scroll = gtk_scrolled_window_new (NULL, NULL); g_object_set (scroll, "shadow-type", GTK_SHADOW_IN, NULL); gtk_box_pack_start (GTK_BOX (box), scroll, TRUE, TRUE, 0);

view = webkit_web_view_new (); gtk_container_add (GTK_CONTAINER (scroll), view); webkit_web_view_load_string (WEBKIT_WEB_VIEW (view), "<html><body></body></html>", "text/html", "UTF-8", NULL);

gtk_widget_show_all (GTK_WIDGET (box)); return window; }

Δημιουργήστε πρώτα ένα αντικείμενο `GtkWindow` και ορίστε τον τίτλο το προεπιλεγμένο μέγεθος του. Συνδέστε επίσης τη συνάρτηση `gtk_main_quit` με το σήμα `delete-event`. Το σήμα `delete-event` εκπέμπεται όταν το παράθυρο κλείνει. Η συνάρτηση `gtk_main_quit` είναι τμήμα του GTK και εγκαταλείπει την εφαρμογή.

Έπειτα δημιουργήστε ένα κάθετο πλαίσιο και προσθέστε το στο παράθυρο. Ένα παράθυρο μπορεί να κρατά μόνο ένα μοναδικό θυγατρικό γραφικό στοιχείο, έτσι χρειαζόσαστε τη χρήση ενός πλαισίου για προσθήκη πολλαπλών γραφικών στοιχείων. Το δεύτερο όρισμα στο `gtk_box_new` ορίζει την ποσότητα συμπλήρωσης (σε εικονοστοιχεία) μεταξύ κάθε θυγατρικού και η επόμενη γραμμή βάζει ένα περίγραμμα έξη εικονοστοιχείων γύρω από όλο το αντικείμενο.

Έπειτα δημιουργείστε ένα αντικείμενο `GtkEntry` και πακετάρετε το στο πλαίσιο. Το τρίτο και τέταρτο όρισμα στο `gtk_box_pack_start` καθορίζει ότι η καταχώριση δεν θα πρέπει να πάρει επιπλέον χώρο που το πλαίσιο έχει διαθέσιμο. Το τέταρτο όρισμα είναι η ποσότητα συμπλήρωσης που θέλετε γύρω από την καταχώριση. Σε αυτή την περίπτωση, ορίζετε τη συμπλήρωση σε μηδέν, επειδή επιτρέπετε στο πλαίσιο να χειριστεί όλη τη συμπλήρωση.

Πριν την προσθήκη μιας προβολής ιστού, πρέπει να δημιουργήσετε ένα κυλιόμενο παράθυρο για να μπει μέσα του. Το κυλιόμενο παράθυρο θα τοποθετήσει γραμμές κύλισης στα δεξιά και κάτω όταν χρειάζεται και θα αποτρέψει την προβολή σας ιστού από το γέμισμα όλης της οθόνης. Αυτή τη φορά, περνάτε `TRUE` και `TRUE` στο `gtk_box_pack_start` για να επιτρέψετε στο κυλιόμενο παράθυρο (και συνεπώς στην προβολή ιστού) να χρησιμοποιήσει οποιοδήποτε διαθέσιμο χώρο στο πλαίσιο.

Τελικά, δημιουργείτε ένα `WebKitWebView` και το προσθέτετε στο κυλιόμενο παράθυρο. Έπειτα φορτώνετε μια πολύ βασική σελίδα HTML στην προβολή ιστού καλώντας `webkit_web_view_load_string` με τα παρακάτω ορίσματα:

## `WEBKIT_WEB_VIEW (view)`

Η ίδια η προβολή. Επειδή η `view` πληκτρολογείτε ως `GtkWidget`, πρέπει να χρησιμοποιήσετε `WEBKIT_WEB_VIEW` για ασφαλή αλλαγή του αντικειμένου.

## `"<html><body></body></html>"`

Το απλούστερο αρχείο HTML που θα μπορούσατε να γράψετε.

## `"text/html"`

Ο τύπος MIME του περιεχομένου που δίνετε. Σε αυτήν την περίπτωση, χρησιμοποιείτε απλό HTML.

## `"UTF-8"`

Η κωδικοποίηση χαρακτήρα του παρεχόμενου περιεχομένου. Αν και χρησιμοποιείτε μόνο ASCII χαρακτήρες, είναι καλή ο καθορισμός UTF-8. Το UTF-8 χρησιμοποιείται ως η προεπιλεγμένη κωδικοποίηση ολοκληρωτικά στο GNOME.

## `NULL`

Η βάση URI. Δεν την χρειαζόσαστε σε αυτό το απλό παράδειγμα, αλλά ίσως θελήσετε να δώσετε ένα file: URI εάν προσθέσετε εικόνες ή άλλα χαρακτηριστικά που θέλετε να χρησιμοποιήσετε σχετικές αναφορές URI.

Κάθε φορά που προσθέτετε ένα γραφικό στοιχείο, πρέπει να καλέσετε `gtk_widget_show` για να γίνει ορατό. Εάν καλέσετε `gtk_widget_show_all` σε ένα περιέκτη γραφικού στοιχείου όπως `GtkBox`, το GTK+ θα εμφανίσει αυτόματα όλα τα γραφικά στοιχεία μέσα στον περιέκτη, σε οποιοδήποτε βάθος. Μερικές φορές δεν θέλετε να καλέσετε `gtk_widget_show_all`, όπως όταν θέλετε να κρύψετε δυναμικά και να εμφανίσετε μερικά γραφικά στοιχεία σε απάντηση συμβάντων.

Τελικά, πρέπει να καλέσετε `gtk_widget_show_all` στο πλαίσιο. Αλλιώς, κανένα από τα γραφικά στοιχεία που δημιουργήσατε δεν θα είναι ορατό. (Το παράθυρο εμφανίζεται στη συνάρτηση `main` με `gtk_widget_show`.)

Αναπτύξτε και εκτελέστε ξανά τον πίνακα μηνύματος. Πρέπει να δείτε ένα παράθυρο με μια καταχώριση κειμένου και μια προβολή ιστού. Δεν κάνει τίποτα ακόμα, επειδή η καταχώριση κειμένου και η προβολή ιστού δεν ξέρουν τίποτα μεταξύ τους.

# Σύνδεση σημάτων

Τώρα, θέλετε να κάνετε τον πίνακα μηνύματος στην πραγματικότητα να κάνει κάτι όταν εισάγετε κείμενο στην καταχώριση κειμένου. Για να το κάνετε αυτό, συνδέστε μια συνάρτηση επανάκλησης στο σήμα `activate` του `entry`. Το GTK+ εκπέμπει το σήμα `activate` όταν ο χρήστης πατά Enter στην καταχώριση. Προσθέστε το παρακάτω στο `create_window`, οπουδήποτε αφού και `entry` και `view` οριστούν:

g_signal_connect (entry, "activate", G_CALLBACK (entry_activate_cb), view);

Τότε πρέπει στην πραγματικότητα να ορίσετε το `entry_activate_cb`. Ορίστε το όπως ακολουθεί, οπουδήποτε πάνω από το `create_window`:

static void entry_activate_cb (GtkEntry *entry, WebKitWebView *view) { WebKitDOMDocument *document; WebKitDOMElement *body, *div;

document = webkit_web_view_get_dom_document (view); body = webkit_dom_document_query_selector (document, "body", NULL); div = webkit_dom_document_create_element (document, "div", NULL); webkit_dom_node_set_text_content (WEBKIT_DOM_NODE (div), gtk_entry_get_text (entry), NULL); webkit_dom_node_append_child (WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (div), NULL); gtk_entry_set_text (entry, ""); }

Το πρώτο πράγμα είναι να πάρετε ένα αντικείμενο `WebKitDOMDocument` που αντιπροσωπεύει το εμφανιζόμενο έγγραφο στο `view`. Οι κλάσεις DOM και οι μέθοδοι στο WebKit επιτρέπουν την επιθεώρηση και χειρισμό του εγγράφου HTML και δουλεύουν πολύ παρόμοια με τα APIs DOM που ήδη μπορεί να ξέρετε από το JavaScript.

Μόλις έχετε το έγγραφο, παίρνετε το στοιχείο `body`, έτσι ώστε να μπορείτε να προσθέσετε τα στοιχεία `div` σε αυτό. Η συνάρτηση `webkit_dom_document_query_selector` επιτρέπει την εύρεση ενός στοιχείου στο έγγραφο χρησιμοποιώντας επιλογείς CSS. Αυτό σας γλυτώνει από το γράψιμο κουραστικών βρόχων για πέρασμα του εγγράφου.

Μετά, δημιουργείτε ένα νέο στοιχείο `div` για κράτημα του μηνύματος. Κάθε στοιχείο που δημιουργείτε πρέπει να προσαρτηθεί σε ένα έγγραφo, έτσι η συνάρτηση στη δημιουργία ενός στοιχείου παίρνει το `WebKitDOMDocument` ως τα πρώτα της ορίσματα. Έπειτα ορίζετε το περιεχόμενο κειμένου του στοιχείου στα περιεχόμενα της καταχώρισης κειμένου. Επειδή το `gtk_entry_get_text` επιστρέφει το `const gchar*`, δεν πρέπει να απελευθερώσετε το αποτέλεσμα.

Τελικά, προσαρτάτε το νέο στοιχείο `div` στο σώμα και καθαρίστε την καταχώριση κειμένου, έτσι ώστε να μπορείτε να τυπώσετε κάτι νέο. Κατασκευή και εκτέλεση του προγράμματος ξανά και έλεγχος του για σας.

# Κάντε το να φαίνεται καλύτερα με CSS

Σε αυτό το σημείο, το πρόγραμμά σας είναι ολότελα λειτουργικό, αλλά όχι πολύ όμορφο. Μπορείτε να μορφοποιήσετε την εμφάνιση μηνύματος με CSS, απλά όπως μπορείτε με κάθε άλλη σελίδα HTML. Υπάρχουν πολλοί τρόποι που θα μπορούσατε να προσαρτήσετε μερικά CSS στη σελίδα: Μπορείτε να τα προσθέσετε στο αρχικό έγγραφο HTML. Θα μπορούσατε να το ενσωματώσετε στο γνώρισμα `style` των στοιχείων `div`. Θα μπορούσατε ακόμα να το κατασκευάσετε προγραμματιστικά χρησιμοποιώντας τα APIs DOM.

Σε αυτό το μάθημα, θα επισυνάψετε το CSS χρησιμοποιώντας την ιδιότητα `user-stylesheet-uri` του προσαρτημένου αντικειμένου `WebKitWebSetting` στην προβολή σας ιστού. Σε μια πιο πλήρη εφαρμογή, θα θέλατε να αποθηκεύσετε και να φορτώσετε το αρχείο HTML. Διατηρώντας τις πληροφορίες μορφοποίησης έξω από το ενεργό HTML σημαίνει ότι μπορείτε να αλλάξετε ολότελα τη μορφοποίηση μες την εφαρμογή σας, χωρίς να χρειαστεί να αλλάξετε τα αρχεία χρήστη. Κανονικά θα εγκαταστήσετε απλά ένα αρχείο μαζί με την εφαρμογή σας, αλλά για να διατηρήσετε απλά κάθε τι σε ένα αρχείο για αυτή την παρουσίαση, θα χρησιμοποιήσουμε ένα κόλπο που λέγεται δεδομένα URI. Πρώτα, ορίστε το CSS ως στατική συμβολοσειρά κοντά στην κορυφή του αρχείου σας.

static const guchar CSS[] = "body { margin: 0; padding: 0; }\n" "div { " " -webkit-border-radius: 2px;" " background: -webkit-gradient(linear, 0% 100%, 0% 0%," " from(#f1f1f1), to(white));" " border: solid 1px #c6c6c6;" " -webkit-box-shadow: 0px 0px 2px #c6c6c6;" " margin: 12px; padding: 6px;" "}";

Ό,τι έχετε σε αυτό το παράδειγμα είναι στοιχεία `div` μέσα σε ένα στοιχείο `body`. Εάν δημιουργήσατε πιο περίπλοκα HTML, θα μπορούσατε να χρησιμοποιήσετε οποιοδήποτε CSS είναι απαραίτητο. Στην πραγματικότητα, εάν είσαστε άνετα με CSS, θα πρέπει να προσπαθήσετε να το αλλάξετε με κάτι που σας αρέσει καλύτερα.

Για εφαρμογή του CSS, ορίζετε τον `user-stylesheet-uri` στην συνάρτηση `create_window`, οπουδήποτε μετά τον ορισμό του `view`.

tmp = g_base64_encode (CSS, strlen((gchar *) CSS)); css = g_strconcat ("data:text/css;charset=utf-8;base64,", tmp, NULL); g_object_set (webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view)), "user-stylesheet-uri", css, NULL); g_free (css); g_free (tmp);

Επίσης, βεβαιωθείτε να προσθέσετε δηλώσεις μεταβλητής για `tmp` και `css` στην κορυφή του `create_window`.

gchar *tmp, *css·

Δεδομένα URI ξεκινούν με data: και μερικές πληροφορίες για τον τύπο περιεχομένου και την κωδικοποίηση δεδομένων. Τα ενεργά δεδομένα ακολουθούν μετά το κόμμα, σε αυτήν την περίπτωση κωδικοποιημένα σε Base64. Αντίθετα με άλλα σχήματα URI όπως http:, ftp: και file:, το σχήμα data: URI δεν καθορίζει πού να βρείτε ένα αρχείο για φόρτωση. Μάλλον, δίνει τα συνολικά περιεχόμενα του αρχείου.

Ο παραπάνω κώδικας πρώτα κωδικοποιεί τους ορισμούς σας CSS σε Base64, έπειτα συνδυάζει αυτό με σταθερή συμβολοσειρά για δημιουργία δεδομένων URI. Η συνάρτηση `g_strconcat` μπορεί να πάρει οποιοδήποτε αριθμό ορισμάτων συμβολοσειράς και να τα συνενώσει όλα μαζί, έτσι έχετε να περάσετε το `NULL` ως τελικό όρισμα για να γνωρίζει πότε να σταματήσει. Μην ξεχάσετε να ελευθερώσετε αυτές τις προσωρινές συμβολοσειρές αφού ορίσετε την ιδιότητα φύλλο μορφοποίησης.

Κατασκευή και εκτέλεση του προγράμματος πάλι. Θα πρέπει τώρα να δουλεύει ακριβώς το ίδιο όπως στο τέλος της τελευταίας ενότητας, εκτός από τα μηνύματα που θα μορφοποιούνται όμορφα με περίγραμμα και λεπτή διαβάθμιση παρασκηνίου.

# Μάθετε περισσότερα

Αυτό το μάθημα δείχνει τη δημιουργία μιας βασικής εφαρμογής χρησιμοποιώντας GTK+ και WebKit, περιλαμβάνοντας την εμφάνιση ενός εγγράφου και επεξεργασία των δεδομένων του. Για τη δημιουργία μιας πραγματικής εφαρμογής, θα θέλετε προφανώς να κάνετε κάτι περισσότερο. Προσπαθήστε να προσθέσετε δικά σας χαρακτηριστικά. Να μερικές ιδέες:

Εάν είσαστε άνετοι με το CSS, δοκιμάστε να αλλάξετε τη μορφοποίηση της εμφάνισης του μηνύματος. Το CSS είναι εύκολο για να ξεκινήσετε, αλλά διαρκώς περισσότερο ισχυρό. Υπάρχει πλήθος μαθημάτων CSS στο διαδίκτυο και σχεδόν κάθε τι που μπορείτε να κάνετε στον ιστό, μπορείτε να το κάνετε με αυτήν την εφαρμογή.

Τώρα αμέσως, χάνετε όλα τα μηνύματά σας όταν κλείνετε τον πίνακα μηνυμάτων. Δοκιμάστε να αποθηκεύσετε τα περιεχόμενα HTML μετά από κάθε ταχυδρόμηση και φορτώστε το αποθηκευμένο αρχείο (εάν υπάρχει) στην εκκίνηση.

Αν κρατάτε τα μηνύματά σας για πολύ χρόνο, θα αρχίσετε να διερωτάστε πότε τα ταχυδρομήσατε. Προσθέσετε ένα σημάδι χρόνου σε κάθε μήνυμα όταν ταχυδρομείται. Θα θέλετε προφανώς να δημιουργήσετε μερικά πρόσθετα θυγατρικά στοιχεία `div` με διαφορετικές κλάσεις που μπορείτε να μορφοποιήσετε σε CSS.

Αυτό το πρόγραμμα κρατά τα μηνύματα για πάντα. Σκεφτείτε τρόπους που θα μπορούσαν να επιτρέψουν στο χρήστη να διαγράψει μηνύματα. Ίσως θέλετε τα μηνύματα να εξαφανίζονται αυτόματα όταν παλιώνουν, ή όταν υπάρχει ένας συγκεκριμένος αριθμός μηνυμάτων πριν από αυτά. Ή θα μπορούσατε να προσθέσετε έναν σύνδεσμο σε κάθε μήνυμα για διαγραφή του. Θα μπορούσατε ακόμα να αντικαταστήσετε το μενού περιεχομένου όταν κάνετε δεξιό κλικ σε μήνυμα. Αυτές τα χαρακτηριστικά περιέχουν περισσότερη περιήγηση του DOM API του WebKit.