1 /* load.c: Load and draw routines for libRUIN
2 * Copyright (C) 2011 Julian Graham
3 *
4 * libRUIN is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <assert.h>
19 #include <curses.h>
20 #include <libguile.h>
21 #include <limits.h>
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "api/api.h"
27 #include "debug.h"
28 #include "handlers/handlers.h"
29 #include "layout.h"
30 #include "load.h"
31 #include "parse.h"
32 #include "render.h"
33 #include "scheme.h"
34 #include "util.h"
35 #include "window.h"
36 #include "xml.h"
37
38 #define GUILE_LOAD_PATH "%load-path"
39
40 static int ruin_initialized = FALSE;
41 static struct sigaction ruin_sigaction_old_action;
42
43 ruin_windows_t *_ruin_windows = NULL;
44
45 extern void _ruin_scm_init_api ();
46 extern void _ruin_scm_init_handlers ();
47 extern void _ruin_box_init ();
48 extern void _ruin_css_init ();
49
ruin_load_layout_and_render(ruin_window_t * w,ruin_node_t * t)50 long ruin_load_layout_and_render (ruin_window_t *w, ruin_node_t *t)
51 {
52 long start_time = ruin_util_current_time_millis ();
53 GList *root_boxes_ptr = NULL;
54
55 w->root_boxes = ruin_layout_generate_and_layout_elements (w, t);
56 root_boxes_ptr = w->root_boxes;
57
58 wclear (w->window);
59
60 while (root_boxes_ptr != NULL)
61 {
62 ruin_box_t *root_box = (ruin_box_t *) root_boxes_ptr->data;
63
64 ruin_debug_print_box_tree (root_box);
65 ruin_render_render_tree (root_box);
66
67 root_boxes_ptr = root_boxes_ptr->next;
68 }
69
70 wrefresh (w->window);
71
72 return ruin_util_current_time_millis () - start_time;
73 }
74
ruin_draw(ruin_window_t * w,SCM doc)75 int ruin_draw (ruin_window_t *w, SCM doc)
76 {
77 ruin_node_t *tree = NULL;
78 int top, left, bottom, right;
79
80 SCM cascade;
81 SCM selection_context;
82
83 enum ruin_xml_dialect lang = ruin_parse_determine_dialect (w, doc);
84
85 cascade = ruin_scheme_scss_make_cascade (w);
86 scm_gc_protect_object (cascade);
87
88 selection_context = ruin_scheme_scss_make_selection_context
89 (w, ruin_scheme_scss_document_interface_sdom,
90 ruin_scheme_scss_make_rendering_interface
91 (w, scm_c_eval_string ("ruin:scss-pseudo-class-handler"),
92 scm_c_eval_string ("ruin:scss-pseudo-element-handler")),
93 cascade);
94 scm_gc_protect_object (selection_context);
95
96 w->cascade = cascade;
97 w->selection_context = selection_context;
98
99 ruin_window_clear (w);
100
101 /* Generate default stylesheet. If the document has an attached stylesheet
102 or adds style on a per-element basis, we can apply that on top of the
103 default. */
104
105 getbegyx (w->window, top, left);
106 getmaxyx (w->window, bottom, right);
107
108 ruin_util_log (w, "window dimensions are %d, %d", right, bottom);
109
110 switch (lang) {
111 case RUIN_XML_DIALECT_XUL:
112 ruin_scheme_scss_set_cascade_agent
113 (w, cascade, scm_copy_tree (_ruin_windows->xul_agent_css));
114 break;
115 case RUIN_XML_DIALECT_XHTML:
116 ruin_scheme_scss_set_cascade_agent
117 (w, cascade, scm_copy_tree (_ruin_windows->xhtml_agent_css));
118 default:
119 break;
120 }
121
122 tree = ruin_parse_document (w, doc);
123
124 ruin_scheme_sdom_dispatch_event (w, tree->doc, "load");
125 ruin_util_log (w, "total time %ldms", ruin_load_layout_and_render (w, tree));
126
127 return TRUE;
128 }
129
ruin_draw_string(ruin_window_t * w,char * doc)130 int ruin_draw_string(ruin_window_t *w, char *doc) {
131 if (doc != NULL) {
132 SCM dom_doc = ruin_scheme_sdom_xml_to_sdom
133 (w, scm_open_input_string(scm_from_locale_string(doc)), SCM_EOL);
134 return ruin_draw(w, dom_doc);
135 }
136 return FALSE;
137 }
138
ruin_draw_file(ruin_window_t * w,char * filename)139 int ruin_draw_file(ruin_window_t *w, char *filename) {
140 if (filename != NULL) {
141 char *abs_path = ruin_util_get_parent_directory(filename);
142 SCM dom_doc = ruin_scheme_sdom_xml_to_sdom
143 (w, scm_open_file(scm_from_locale_string(filename),
144 scm_from_locale_string("r")),
145 SCM_EOL);
146 scm_call_2(scm_c_eval_string("sdom:set-document-uri!"), dom_doc,
147 scm_string_append(scm_list_2(scm_from_locale_string("file://"),
148 scm_from_locale_string(abs_path))));
149 free(abs_path);
150 return ruin_draw(w, dom_doc);
151 }
152 return FALSE;
153 }
154
_set_ruin_temp_load_path(SCM oldval,char * varname)155 void _set_ruin_temp_load_path(SCM oldval, char *varname) {
156 char *tmpval = getenv(varname);
157 scm_set_car_x(scm_c_eval_string(GUILE_LOAD_PATH),
158 scm_from_locale_string
159 (tmpval != NULL ? tmpval : RUIN_SCHEME_PATH));
160 scm_set_cdr_x(scm_c_eval_string(GUILE_LOAD_PATH), oldval);
161 return;
162 }
163
ruin_init()164 int ruin_init() {
165 SCM old_path = scm_list_copy(scm_c_eval_string(GUILE_LOAD_PATH));
166 extern pthread_mutex_t _ruin_util_id_lock;
167
168 struct sigaction new_action;
169 new_action.sa_sigaction = ruin_window_signal_handler_SIGWINCH;
170 new_action.sa_flags = SA_SIGINFO;
171 sigemptyset(&new_action.sa_mask);
172
173 if (ruin_initialized)
174 return FALSE;
175
176 pthread_mutex_init(&_ruin_util_id_lock, NULL);
177 (void) sigaction(SIGWINCH, NULL, &ruin_sigaction_old_action);
178 (void) sigaction(SIGWINCH, &new_action, NULL);
179
180 /*
181 * Upon load, `(rnrs exceptions)' registers the r6rs:exception
182 * exception-printer.
183 */
184
185 scm_c_use_module("rnrs exceptions");
186
187 _set_ruin_temp_load_path(old_path, "RUIN_SCHEME_SXML_PATH");
188 scm_c_use_module("sxml ssax");
189
190 _set_ruin_temp_load_path(old_path, "RUIN_SCHEME_SDOM_PATH");
191 scm_c_use_module("sdom core");
192 scm_c_use_module("sdom events");
193
194 _set_ruin_temp_load_path(old_path, "RUIN_SCHEME_SCSS_PATH");
195 scm_c_use_module("scss scss");
196 scm_c_use_module("scss interface sdom");
197 scm_set_car_x(scm_c_eval_string(GUILE_LOAD_PATH), SCM_CAR(old_path));
198 scm_set_cdr_x(scm_c_eval_string(GUILE_LOAD_PATH), SCM_CDR(old_path));
199
200 ruin_parse_init ();
201
202 /* Also initialize our own Scheme API. */
203
204 ruin_scheme_init ();
205 _ruin_scm_init_api ();
206 _ruin_scm_init_handlers ();
207 _ruin_css_init ();
208 _ruin_box_init ();
209
210 /* Set up a default color pair... */
211 init_pair(1, COLOR_WHITE, COLOR_BLACK);
212
213 _ruin_windows = ruin_windows_new();
214 return TRUE;
215 }
216
ruin_shutdown()217 void ruin_shutdown() {
218 extern pthread_mutex_t _ruin_util_id_lock;
219 if (!ruin_initialized)
220 return;
221 pthread_mutex_destroy(&_ruin_util_id_lock);
222 ruin_windows_free(_ruin_windows);
223 (void) sigaction(SIGWINCH, &ruin_sigaction_old_action, NULL);
224 return;
225 }
226