1 /* window.c: Window-management 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 <glib.h>
19 #ifdef LINUX
20 #include <pty.h>
21 #endif /* LINUX */
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/ioctl.h>
26 
27 #include "layout.h"
28 #include "load.h"
29 #include "parse.h"
30 #include "scheme.h"
31 #include "util.h"
32 #include "window.h"
33 
34 extern void ruin_box_free (ruin_box_t *);
35 extern ruin_windows_t *_ruin_windows;
36 static pthread_mutex_t ruin_window_signal_handler_SIGWINCH_entry_lock;
37 
resize_window(gpointer key,gpointer value,gpointer user_data)38 static void resize_window (gpointer key, gpointer value, gpointer user_data)
39 {
40   ruin_window_t *window = (ruin_window_t *) value;
41   int *newxy = (int *) user_data;
42   int oldx = 0, oldy = 0, newx = 0, newy = 0;
43 
44   ruin_box_t *root_box = (ruin_box_t *) g_list_nth_data (window->root_boxes, 0);
45   ruin_node_t *generator = root_box->generator;
46   GList *root_box_ptr = window->root_boxes;
47 
48   oldx = window->width;
49   oldy = window->height;
50 
51   newx = newxy[0];
52   newy = newxy[1];
53 
54   if (oldx != newx || oldy != newy)
55     {
56       window->width = newx;
57       window->height = newy;
58 
59       resizeterm (newy, newx);
60       ruin_load_layout_and_render (window, generator);
61 
62       while (root_box_ptr != NULL)
63 	{
64 	  ruin_box_t *old_box = (ruin_box_t *) root_box_ptr->data;
65 	  ruin_box_free (old_box);
66 	  root_box_ptr = root_box_ptr->next;
67 	}
68     }
69 }
70 
ruin_window_signal_handler_SIGWINCH(int n,siginfo_t * s,void * u)71 void ruin_window_signal_handler_SIGWINCH (int n, siginfo_t *s, void *u)
72 {
73   static int busy = 0;
74   struct winsize ws;
75   int newxy[2];
76 
77   pthread_mutex_lock (&ruin_window_signal_handler_SIGWINCH_entry_lock);
78   if (busy)
79     {
80       pthread_mutex_unlock (&ruin_window_signal_handler_SIGWINCH_entry_lock);
81       return;
82     }
83   pthread_mutex_unlock (&ruin_window_signal_handler_SIGWINCH_entry_lock);
84   busy = TRUE;
85 
86   (void) ioctl (0, TIOCGWINSZ, &ws);
87 
88   newxy[0] = ws.ws_col;
89   newxy[1] = ws.ws_row;
90 
91   g_hash_table_foreach (_ruin_windows->windows, resize_window, newxy);
92 
93   busy = FALSE;
94 }
95 
ruin_windows_new()96 ruin_windows_t *ruin_windows_new ()
97 {
98   char *xul = NULL;
99   char *xhtml = NULL;
100 
101   char *env_val = getenv ("RUIN_CSS_PATH");
102 
103   SCM port = SCM_EOL;
104 
105   ruin_windows_t *t = calloc (1, sizeof (ruin_windows_t));
106   t->windows = g_hash_table_new (g_str_hash, g_str_equal);
107 
108   if (env_val == NULL)
109     env_val = RUIN_CSS_PATH;
110 
111   xul = calloc (strlen (env_val) + 16, sizeof(char));
112   xhtml = calloc (strlen (env_val) + 18, sizeof(char));
113   strcat (xul, "file://");
114   strcat (xul, env_val);
115   strcat (xul, "/xul.css");
116   strcat (xhtml, "file://");
117   strcat (xhtml, env_val);
118   strcat (xhtml, "/xhtml.css");
119 
120   port = scm_open_file
121     (scm_from_locale_string (xul + 7), scm_from_locale_string ("r"));
122   t->xul_agent_css = ruin_scheme_scss_css_to_scss_port (NULL, port, xul);
123 
124   port = scm_open_file
125     (scm_from_locale_string (xhtml + 7), scm_from_locale_string ("r"));
126   t->xhtml_agent_css = ruin_scheme_scss_css_to_scss_port (NULL, port, xhtml);
127 
128   free (xul);
129   free (xhtml);
130 
131   pthread_mutex_init (&ruin_window_signal_handler_SIGWINCH_entry_lock, NULL);
132 
133   return t;
134 }
135 
ruin_windows_free(ruin_windows_t * t)136 void ruin_windows_free (ruin_windows_t *t)
137 {
138   free (t->windows);
139   scm_gc_unprotect_object (t->xul_agent_css);
140   scm_gc_unprotect_object (t->xhtml_agent_css);
141   free (t);
142 }
143 
ruin_window_new(WINDOW * w,FILE * f)144 ruin_window_t *ruin_window_new (WINDOW *w, FILE *f)
145 {
146   ruin_window_t *t = calloc (1, sizeof (ruin_window_t));
147   char *tmp = NULL, *tmp_ptr = NULL;
148   int tmp_val = 0;
149 
150   t->window = w;
151   t->log = f;
152   t->render_state = calloc (1, sizeof (ruin_window_render_state_t));
153 
154   t->internal_id = ruin_util_generate_id ();
155   g_hash_table_insert
156     (_ruin_windows->windows, ruin_util_long_to_string (t->internal_id), t);
157 
158   t->ids = ruin_util_hash_new ();
159   t->internal_ids = ruin_util_hash_new ();
160 
161   if ((tmp = getenv (RUIN_WINDOW_FONT_HEIGHT_ENV)) &&
162       ((tmp_val = strtol (tmp, &tmp_ptr, 10)) > 0) &&
163       (tmp != tmp_ptr))
164     t->font_height = tmp_val;
165   else t->font_height = RUIN_WINDOW_DEFAULT_FONT_HEIGHT;
166 
167   if ((tmp = getenv (RUIN_WINDOW_FONT_WIDTH_ENV)) &&
168       ((tmp_val = strtol (tmp, &tmp_ptr, 10)) > 0) &&
169       (tmp != tmp_ptr))
170     t->font_width = tmp_val;
171   else t->font_width = RUIN_WINDOW_DEFAULT_FONT_WIDTH;
172 
173   if ((tmp = getenv (RUIN_WINDOW_DPI_ENV)) &&
174       ((tmp_val = strtol (tmp, &tmp_ptr, 10)) > 0) &&
175       (tmp != tmp_ptr))
176     t->dpi = tmp_val;
177   else t->dpi = RUIN_WINDOW_DEFAULT_DPI;
178 
179   getmaxyx (w, t->height, t->width);
180 
181   if (_ruin_windows->current_window == NULL)
182     _ruin_windows->current_window = t;
183 
184   return t;
185 }
186 
ruin_window_free(ruin_window_t * t)187 void ruin_window_free (ruin_window_t *t)
188 {
189   g_hash_table_remove
190     (_ruin_windows->windows, ruin_util_long_to_string (t->internal_id));
191 
192   ruin_window_clear (t);
193   ruin_util_hash_free (t->ids);
194   ruin_util_hash_free (t->internal_ids);
195 
196   free (t->render_state);
197   free (t);
198   return;
199 }
200 
ruin_window_clear(ruin_window_t * w)201 void ruin_window_clear (ruin_window_t *w)
202 {
203   ruin_util_hash_clear (w->ids);
204   ruin_util_hash_clear (w->internal_ids);
205   return;
206 }
207 
ruin_window_lookup_scm(SCM elt)208 ruin_node_t *ruin_window_lookup_scm (SCM elt)
209 {
210   ruin_window_t *containing_win = ruin_window_lookup_window (elt);
211   if (containing_win != NULL)
212     {
213       SCM res = SCM_EOL;
214       if (scm_eq_p (res, SCM_EOL) == SCM_BOOL_T)
215 	ruin_util_log (containing_win, "found containing window but not node");
216       return (ruin_node_t *)
217 	ruin_util_string_to_ptr (scm_to_locale_string (res));
218     }
219   return NULL;
220 }
221 
ruin_window_lookup_window(SCM elt)222 ruin_window_t *ruin_window_lookup_window (SCM elt)
223 {
224   return NULL;
225 }
226 
ruin_get_current_window()227 ruin_window_t *ruin_get_current_window ()
228 {
229   return ruin_window_get_current_window ();
230 }
231 
ruin_window_get_current_window()232 ruin_window_t *ruin_window_get_current_window ()
233 {
234   return _ruin_windows->current_window;
235 }
236 
ruin_set_current_window(ruin_window_t * w)237 void ruin_set_current_window (ruin_window_t *w)
238 {
239   ruin_window_set_current_window (w);
240   /* TODO: Render it! */
241 }
242 
ruin_window_set_current_window(ruin_window_t * w)243 void ruin_window_set_current_window (ruin_window_t *w)
244 {
245   _ruin_windows->current_window = w;
246 }
247