1 /*
2  * Copyright 2010 Ole Loots <ole@monochrom.net>
3  *
4  * This file is part of NetSurf, http://www.netsurf-browser.org/
5  *
6  * NetSurf is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * NetSurf is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * \file
21  * Implements the NetSurf Browser window, or passed functionality to
22  * the appropriate widget's.
23  *
24  */
25 
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <limits.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <stdbool.h>
34 #include <assert.h>
35 #include <math.h>
36 #include <osbind.h>
37 
38 #include <mt_gem.h>
39 
40 #include "utils/log.h"
41 #include "utils/nsurl.h"
42 #include "netsurf/browser_window.h"
43 #include "netsurf/mouse.h"
44 #include "netsurf/plotters.h"
45 #include "netsurf/keypress.h"
46 
47 #include "atari/res/netsurf.rsh"
48 #include "atari/gemtk/gemtk.h"
49 #include "atari/ctxmenu.h"
50 #include "atari/gui.h"
51 #include "atari/rootwin.h"
52 #include "atari/misc.h"
53 #include "atari/plot/plot.h"
54 #include "atari/toolbar.h"
55 #include "atari/statusbar.h"
56 #include "atari/search.h"
57 #include "atari/osspec.h"
58 #include "atari/encoding.h"
59 #include "atari/redrawslots.h"
60 #include "atari/toolbar.h"
61 #include "atari/findfile.h"
62 #include "atari/bitmap.h"
63 
64 extern struct gui_window *input_window;
65 extern EVMULT_OUT aes_event_out;
66 extern GRECT desk_area;
67 
68 struct rootwin_data_s {
69     struct s_gui_win_root *rootwin;
70 };
71 
72 /* -------------------------------------------------------------------------- */
73 /* Static module event handlers                                               */
74 /* -------------------------------------------------------------------------- */
75 static void on_redraw(ROOTWIN *rootwin, short msg[8]);
76 static void on_resized(ROOTWIN *rootwin);
77 static void on_file_dropped(ROOTWIN *rootwin, short msg[8]);
78 static short on_window_key_input(ROOTWIN * rootwin, unsigned short nkc);
79 static void on_content_mouse_click(ROOTWIN *rootwin);
80 static void on_content_mouse_move(ROOTWIN *rootwin, GRECT *content_area);
81 static void	toolbar_redraw_cb(GUIWIN *win, uint16_t msg, GRECT *clip);
82 
83 bool gui_window_get_scroll(struct gui_window *w, int *sx, int *sy);
84 
85 static bool redraw_active = false;
86 
87 static const struct redraw_context rootwin_rdrw_ctx = {
88     .interactive = true,
89     .background_images = true,
90     .plot = &atari_plotters
91 };
92 
handle_event(GUIWIN * win,EVMULT_OUT * ev_out,short msg[8])93 static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
94 {
95     short retval = 0;
96     GRECT area;
97     static bool prev_url = false;
98     struct rootwin_data_s * data = gemtk_wm_get_user_data(win);
99     struct gui_window *tmp;
100 
101 
102     if ((ev_out->emo_events & MU_MESAG) != 0) {
103         // handle message
104         //printf("root win msg: %d\n", msg[0]);
105         switch (msg[0]) {
106 
107         case WM_REDRAW:
108 			NSLOG(netsurf, INFO, "WM_REDRAW");
109             on_redraw(data->rootwin, msg);
110             break;
111 
112         case WM_REPOSED:
113         case WM_SIZED:
114         case WM_MOVED:
115         case WM_FULLED:
116 			NSLOG(netsurf, INFO, "WM_SIZED");
117             on_resized(data->rootwin);
118             break;
119 
120         case WM_ICONIFY:
121             // TODO: find next active gui window and schedule redraw for that.
122 			tmp = window_list;
123 			while(tmp != NULL){
124 				if(tmp->root != data->rootwin){
125 					gemtk_wm_send_msg(tmp->root->win, WM_TOPPED, 0, 0, 0, 0);
126 					break;
127 				}
128 				tmp = tmp->next;
129 			}
130             break;
131 
132         case WM_TOPPED:
133         case WM_NEWTOP:
134         case WM_UNICONIFY:
135 			NSLOG(netsurf, INFO, "WM_TOPPED");
136             gui_set_input_gui_window(data->rootwin->active_gui_window);
137             //window_restore_active_gui_window(data->rootwin);
138             // TODO: use something like "restore_active_gui_window_state()"
139 
140             break;
141 
142         case WM_CLOSED:
143             // TODO: this needs to iterate through all gui windows and
144             // check if the rootwin is this window...
145             if (data->rootwin->active_gui_window != NULL) {
146                 NSLOG(netsurf, INFO, "WM_CLOSED initiated destroy for bw %p",
147                       data->rootwin->active_gui_window->browser->bw);
148                 browser_window_destroy(
149                     data->rootwin->active_gui_window->browser->bw);
150             }
151             break;
152 
153         case AP_DRAGDROP:
154             on_file_dropped(data->rootwin, msg);
155             break;
156 
157         case WM_TOOLBAR:
158             toolbar_mouse_input(data->rootwin->toolbar, msg[4], msg[7]);
159             break;
160 
161         default:
162             break;
163         }
164     }
165     if ((ev_out->emo_events & MU_KEYBD) != 0) {
166 
167         // handle key
168         uint16_t nkc = gem_to_norm( (short)ev_out->emo_kmeta,
169                                     (short)ev_out->emo_kreturn);
170 		NSLOG(netsurf, INFO, "rootwin MU_KEYBD input, nkc: %x\n", nkc);
171         retval = on_window_key_input(data->rootwin, nkc);
172         // printf("on_window_key_input: %d\n", retval);
173 
174     }
175     if ((ev_out->emo_events & MU_BUTTON) != 0) {
176 		NSLOG(netsurf, INFO,
177                       "rootwin MU_BUTTON input, x: %d, y: %d\n",
178                       ev_out->emo_mouse.p_x,
179                       ev_out->emo_mouse.p_x);
180         window_get_grect(data->rootwin, BROWSER_AREA_CONTENT,
181                          &area);
182         if (POINT_WITHIN(ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_y,
183                          area)) {
184             on_content_mouse_click(data->rootwin);
185         }
186     }
187     if ((ev_out->emo_events & (MU_M1)) != 0) {
188 
189         short ghandle = wind_find(ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_y);
190 
191         if (data->rootwin->aes_handle==ghandle) {
192             // The window found at x,y is an gui_window
193             // and it's the input window.
194             window_get_grect(data->rootwin, BROWSER_AREA_CONTENT,
195                              &area);
196             if (POINT_WITHIN(ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_y,
197                              area)) {
198                 on_content_mouse_move(data->rootwin, &area);
199             } else {
200                 GRECT tb_area;
201                 window_get_grect(data->rootwin, BROWSER_AREA_URL_INPUT, &tb_area);
202                 if (POINT_WITHIN(ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_y,
203                                  tb_area)) {
204                     gem_set_cursor(&gem_cursors.ibeam);
205                     prev_url = true;
206                 } else {
207                     if(prev_url) {
208                         struct gui_window *gw;
209                         gw = window_get_active_gui_window(data->rootwin);
210                         gem_set_cursor(gw->cursor);
211                         prev_url = false;
212                     }
213                 }
214             }
215         }
216     }
217 
218     return(retval);
219 }
220 
221 /* -------------------------------------------------------------------------- */
222 /* Module public functions:                                                   */
223 /* -------------------------------------------------------------------------- */
224 
window_create(struct gui_window * gw,struct browser_window * bw,struct gui_window * existing,unsigned long inflags)225 int window_create(struct gui_window * gw,
226                   struct browser_window * bw,
227                   struct gui_window * existing,
228                   unsigned long inflags)
229 {
230     int err = 0;
231     bool tb, sb;
232     int flags;
233     struct rootwin_data_s *data;
234     struct gemtk_wm_scroll_info_s *slid;
235 
236     tb = (inflags & WIDGET_TOOLBAR);
237     sb = (inflags & WIDGET_STATUSBAR);
238 
239     flags = CLOSER | MOVER | NAME | FULLER | SMALLER;
240     if( inflags & WIDGET_SCROLL ) {
241         flags |= (UPARROW | DNARROW | LFARROW | RTARROW | VSLIDE | HSLIDE);
242     }
243     if( inflags & WIDGET_RESIZE ) {
244         flags |= ( SIZER );
245     }
246     if( inflags & WIDGET_STATUSBAR ) {
247         flags |= ( INFO );
248     }
249 
250     gw->root = malloc(sizeof(struct s_gui_win_root));
251     if (gw->root == NULL)
252         return(-1);
253     memset(gw->root, 0, sizeof(struct s_gui_win_root) );
254     gw->root->title = malloc(atari_sysinfo.aes_max_win_title_len+1);
255 
256     redraw_slots_init(&gw->root->redraw_slots, 8);
257 
258     gw->root->aes_handle = wind_create(flags, 40, 40, desk_area.g_w,
259                                        desk_area.g_h);
260     if(gw->root->aes_handle<0) {
261         free(gw->root->title);
262         free(gw->root);
263         return( -1 );
264     }
265     gw->root->win = gemtk_wm_add(gw->root->aes_handle,
266                                GEMTK_WM_FLAG_PREPROC_WM | GEMTK_WM_FLAG_RECV_PREPROC_WM, handle_event);
267 
268     data = malloc(sizeof(struct rootwin_data_s));
269     data->rootwin = gw->root;
270     gemtk_wm_set_user_data(gw->root->win, (void*)data);
271     slid = gemtk_wm_get_scroll_info(gw->root->win);
272     slid->y_unit_px = 32;
273     slid->x_unit_px = 32;
274 
275     /* create */
276     if(tb) {
277         gw->root->toolbar = toolbar_create(gw->root);
278         assert(gw->root->toolbar);
279         gemtk_wm_set_toolbar(gw->root->win, gw->root->toolbar->form, 0, 0);
280 		gemtk_wm_set_toolbar_redraw_func(gw->root->win, toolbar_redraw_cb);
281     } else {
282         gw->root->toolbar = NULL;
283     }
284 
285     /* create browser component: */
286     gw->browser = (struct s_browser *)malloc( sizeof(struct s_browser));
287 
288     assert(gw->browser);
289 
290     gw->browser->bw = bw;
291 
292     /* create statusbar component: */
293     if(sb) {
294         gw->root->statusbar = sb_create( gw );
295     } else {
296         gw->root->statusbar = NULL;
297     }
298 
299     // Setup some window defaults:
300     wind_set_str(gw->root->aes_handle, WF_NAME, (char*)"NetSurf");
301     wind_set(gw->root->aes_handle, WF_OPTS, 1, WO0_FULLREDRAW, 0, 0);
302     wind_set(gw->root->aes_handle, WF_OPTS, 1, WO0_NOBLITW, 0, 0);
303     wind_set(gw->root->aes_handle, WF_OPTS, 1, WO0_NOBLITH, 0, 0);
304 
305     if (inflags & WIN_TOP) {
306         window_set_focus(gw->root, BROWSER, gw->browser);
307     }
308 
309     return (err);
310 }
311 
window_unref_gui_window(ROOTWIN * rootwin,struct gui_window * gw)312 void window_unref_gui_window(ROOTWIN *rootwin, struct gui_window *gw)
313 {
314     struct gui_window *w;
315     input_window = NULL;
316 
317     NSLOG(netsurf, INFO, "window: %p, gui_window: %p", rootwin, gw);
318 
319     w = window_list;
320     // find the next active tab:
321     while( w != NULL ) {
322         if(w->root == rootwin && w != gw) {
323         	NSLOG(netsurf, INFO, "activating next tab %p", w);
324             gui_set_input_gui_window(w);
325             break;
326         }
327         w = w->next;
328     }
329     if(input_window == NULL) {
330         // the last gui window for this rootwin was removed:
331         redraw_slots_free(&rootwin->redraw_slots);
332         window_destroy(rootwin);
333     }
334 }
335 
window_destroy(ROOTWIN * rootwin)336 int window_destroy(ROOTWIN *rootwin)
337 {
338     int err = 0;
339     struct gui_window *w;
340 
341     assert(rootwin != NULL);
342 
343     NSLOG(netsurf, INFO, "%p", rootwin);
344 
345     if (gemtk_wm_get_user_data(rootwin->win) != NULL) {
346         free(gemtk_wm_get_user_data(rootwin->win));
347     }
348 
349     // make sure we do not destroy windows which have gui_windows attached:
350     w = window_list;
351     while( w != NULL ) {
352         if(w->root == rootwin) {
353             assert(rootwin == NULL);
354         }
355         w = w->next;
356     }
357 
358     if (rootwin->toolbar)
359         toolbar_destroy(rootwin->toolbar);
360 
361     if(rootwin->statusbar)
362         sb_destroy(rootwin->statusbar);
363 
364     if(rootwin->title)
365         free(rootwin->title);
366 
367     gemtk_wm_remove(rootwin->win);
368     wind_close(rootwin->aes_handle);
369     wind_delete(rootwin->aes_handle);
370     free(rootwin);
371     return(err);
372 }
373 
374 
window_open(ROOTWIN * rootwin,struct gui_window * gw,GRECT pos)375 void window_open(ROOTWIN *rootwin, struct gui_window *gw, GRECT pos)
376 {
377     GRECT g;
378 
379     rootwin->active_gui_window = gw;
380 
381     assert(rootwin->active_gui_window != NULL);
382 
383     wind_open(rootwin->aes_handle, pos.g_x, pos.g_y, pos.g_w, pos.g_h );
384     wind_set_str(rootwin->aes_handle, WF_NAME, (char *)"");
385 
386     rootwin->active_gui_window->browser->attached = true;
387     if(rootwin->statusbar != NULL) {
388         sb_attach(rootwin->statusbar, rootwin->active_gui_window);
389     }
390 
391     /* Set initial size of the toolbar region: */
392     gemtk_wm_get_grect(rootwin->win, GEMTK_WM_AREA_TOOLBAR, &g);
393     toolbar_set_attached(rootwin->toolbar, true);
394     toolbar_set_dimensions(rootwin->toolbar, &g);
395 
396     /* initially hide the search area of the toolbar: */
397 	window_close_search(rootwin);
398 
399     window_update_back_forward(rootwin);
400 
401     window_set_focus(rootwin, BROWSER, rootwin->active_gui_window->browser);
402 }
403 
window_restore_active_gui_window(ROOTWIN * rootwin)404 void window_restore_active_gui_window(ROOTWIN *rootwin)
405 {
406 	GRECT tb_area;
407 	struct gui_window *gw;
408 
409 	NSLOG(netsurf, INFO, "rootwin %p", rootwin);
410 
411 	assert(rootwin->active_gui_window);
412 
413 	gw = rootwin->active_gui_window;
414 
415         window_set_icon(rootwin, gw->icon);
416         window_set_stauts(rootwin, gw->status);
417         window_set_title(rootwin, gw->title);
418 
419 	if (gw->search != NULL) {
420 		// TODO: update search session (especially browser window)
421         }
422 
423 	toolbar_get_grect(rootwin->toolbar, 0, &tb_area);
424 	gemtk_wm_set_toolbar_size(rootwin->win, tb_area.g_h);
425 
426 	window_update_back_forward(rootwin);
427 
428         toolbar_set_url(rootwin->toolbar, gw->url);
429 }
430 
431 
432 /* update back forward buttons (see tb_update_buttons (bug) ) */
window_update_back_forward(struct s_gui_win_root * rootwin)433 void window_update_back_forward(struct s_gui_win_root *rootwin)
434 {
435     struct gui_window * active_gw = rootwin->active_gui_window;
436     toolbar_update_buttons(rootwin->toolbar, active_gw->browser->bw, -1);
437 }
438 
window_set_stauts(struct s_gui_win_root * rootwin,char * text)439 void window_set_stauts(struct s_gui_win_root *rootwin, char * text)
440 {
441     assert(rootwin != NULL);
442 
443     CMP_STATUSBAR sb = rootwin->statusbar;
444 
445     if( sb == NULL)
446         return;
447 
448     if(text != NULL)
449         sb_set_text(sb, text);
450     else
451         sb_set_text(sb, "");
452 }
453 
window_set_title(struct s_gui_win_root * rootwin,char * title)454 void window_set_title(struct s_gui_win_root * rootwin, char *title)
455 {
456     wind_set_str(rootwin->aes_handle, WF_NAME, title);
457 }
458 
window_scroll_by(ROOTWIN * root,int sx,int sy)459 void window_scroll_by(ROOTWIN *root, int sx, int sy)
460 {
461     struct gemtk_wm_scroll_info_s *slid = gemtk_wm_get_scroll_info(root->win);
462 
463     if (sx < 0) {
464         sx = 0;
465     }
466     if (sy < 0) {
467         sy = 0;
468     }
469     int xunits = sx / slid->x_unit_px;
470     int yunits = sy / slid->y_unit_px;
471 
472     gemtk_wm_scroll(root->win, GEMTK_WM_VSLIDER, yunits - slid->y_pos, false);
473     gemtk_wm_scroll(root->win, GEMTK_WM_HSLIDER, xunits - slid->x_pos, false);
474     gemtk_wm_update_slider(root->win, GEMTK_WM_VH_SLIDER);
475 }
476 
477 /**
478 * Set the dimensions of the scrollable content.
479 *
480 */
window_set_content_size(ROOTWIN * rootwin,int width,int height)481 void window_set_content_size(ROOTWIN *rootwin, int width, int height)
482 {
483     GRECT area;
484     struct gemtk_wm_scroll_info_s *slid = gemtk_wm_get_scroll_info(rootwin->win);
485 
486     window_get_grect(rootwin, BROWSER_AREA_CONTENT, &area);
487 
488     slid->x_units = (width/slid->x_unit_px);
489     slid->y_units = (height/slid->y_unit_px);
490     if(slid->x_units < slid->x_pos)
491         slid->x_pos = 0;
492     if(slid->y_units < slid->y_pos)
493         slid->y_pos = 0;
494     gemtk_wm_update_slider(rootwin->win, GEMTK_WM_VH_SLIDER);
495 }
496 
497 /* set focus to an arbitary element */
window_set_focus(struct s_gui_win_root * rootwin,enum focus_element_type type,void * element)498 void window_set_focus(struct s_gui_win_root *rootwin,
499                       enum focus_element_type type, void * element)
500 {
501     assert(rootwin != NULL);
502 
503     if (rootwin->focus.type != type || rootwin->focus.element != element) {
504         NSLOG(netsurf, INFO, "Set focus: %p (%d)\n", element, type);
505         rootwin->focus.type = type;
506         rootwin->focus.element = element;
507 		switch( type ) {
508 
509 		case URL_WIDGET:
510                 // TODO: make something like: toolbar_text_select_all();
511 			toolbar_key_input(rootwin->toolbar, (short)(NKF_CTRL | 'A') );
512 /*
513 			ta = toolbar_get_textarea(rootwin->toolbar,
514 										URL_INPUT_TEXT_AREA);
515 			textarea_keypress(ta, NS_KEY_SELECT_ALL);
516 			*/
517 			break;
518 
519 		case SEARCH_INPUT:
520 			gemtk_wm_set_toolbar_edit_obj(rootwin->win, TOOLBAR_TB_SRCH, 0);
521 			break;
522 
523 		default:
524 			break;
525 
526 		}
527     }
528 }
529 
530 /* check if the url widget has focus */
window_url_widget_has_focus(struct s_gui_win_root * rootwin)531 bool window_url_widget_has_focus(struct s_gui_win_root *rootwin)
532 {
533     assert(rootwin != NULL);
534 
535     if (rootwin->focus.type == URL_WIDGET) {
536         return true;
537     }
538     return false;
539 }
540 
541 /* check if an arbitary window widget / or frame has the focus */
window_widget_has_focus(struct s_gui_win_root * rootwin,enum focus_element_type t,void * element)542 bool window_widget_has_focus(struct s_gui_win_root *rootwin,
543                              enum focus_element_type t, void * element)
544 {
545     assert(rootwin != NULL);
546     if( element == NULL  ) {
547         return((rootwin->focus.type == t));
548     }
549 
550     return((element == rootwin->focus.element && t == rootwin->focus.type));
551 }
552 
window_set_icon(ROOTWIN * rootwin,struct bitmap * bmp)553 void window_set_icon(ROOTWIN *rootwin, struct bitmap * bmp )
554 {
555     rootwin->icon = bmp;
556     /* redraw window when it is iconyfied: */
557     if (rootwin->icon != NULL) {
558         if (gemtk_wm_get_state(rootwin->win) & GEMTK_WM_STATUS_ICONIFIED) {
559             window_redraw_favicon(rootwin, NULL);
560         }
561     }
562 }
563 
window_set_active_gui_window(ROOTWIN * rootwin,struct gui_window * gw)564 void window_set_active_gui_window(ROOTWIN *rootwin, struct gui_window *gw)
565 {
566 	struct gui_window *old_gw = rootwin->active_gui_window;
567 
568 	NSLOG(netsurf, INFO, "gw %p", gw);
569 
570         if (rootwin->active_gui_window != NULL) {
571                 if(rootwin->active_gui_window == gw) {
572                         NSLOG(netsurf, INFO, "nothing to do...");
573                         return;
574                 }
575         }
576 
577 	// TODO: when the window isn't on top, initiate WM_TOPPED.
578 
579 	rootwin->active_gui_window = gw;
580 	if (old_gw != NULL) {
581 		NSLOG(netsurf, INFO, "restoring window...");
582 		window_restore_active_gui_window(rootwin);
583 	}
584 }
585 
window_get_active_gui_window(ROOTWIN * rootwin)586 struct gui_window * window_get_active_gui_window(ROOTWIN * rootwin)
587 {
588     return(rootwin->active_gui_window);
589 }
590 
window_get_scroll(ROOTWIN * rootwin,int * x,int * y)591 void window_get_scroll(ROOTWIN *rootwin, int *x, int *y)
592 {
593     struct gemtk_wm_scroll_info_s *slid;
594 
595     slid = gemtk_wm_get_scroll_info(rootwin->win);
596 
597     *x = slid->x_pos * slid->x_unit_px;
598     *y = slid->y_pos * slid->y_unit_px;
599 }
600 
window_get_grect(ROOTWIN * rootwin,enum browser_area_e which,GRECT * d)601 void window_get_grect(ROOTWIN *rootwin, enum browser_area_e which, GRECT *d)
602 {
603 
604     d->g_x = 0;
605     d->g_y = 0;
606     d->g_w = 0;
607     d->g_h = 0;
608 
609     if (which == BROWSER_AREA_TOOLBAR) {
610         // gemtk_wm_get_grect(rootwin->win, GEMTK_WM_AREA_TOOLBAR, d);
611         toolbar_get_grect(rootwin->toolbar, 0, d);
612 
613     } else if (which == BROWSER_AREA_CONTENT) {
614 
615         GRECT tb_area;
616 
617         gemtk_wm_get_grect(rootwin->win, GEMTK_WM_AREA_WORK, d);
618         toolbar_get_grect(rootwin->toolbar, 0, &tb_area);
619 
620         d->g_y += tb_area.g_h;
621         d->g_h -= tb_area.g_h;
622 
623     } else if (which == BROWSER_AREA_URL_INPUT) {
624 
625         toolbar_get_grect(rootwin->toolbar, TOOLBAR_AREA_URL, d);
626 
627     } else if (which == BROWSER_AREA_SEARCH) {
628         // todo: check if search is visible
629         toolbar_get_grect(rootwin->toolbar, TOOLBAR_AREA_SEARCH, d);
630     } else {
631 
632     }
633 
634 
635     // sanitize the results
636     if (d->g_h < 0) {
637         d->g_h = 0;
638     }
639     if (d->g_w < 0) {
640         d->g_w = 0;
641     }
642 
643     //printf("window_get_grect %d:", which);
644     //dbg_grect("", d);
645 
646 }
647 
648 
window_open_search(ROOTWIN * rootwin,bool reformat)649 void window_open_search(ROOTWIN *rootwin, bool reformat)
650 {
651 	struct browser_window *bw;
652 	struct gui_window *gw;
653 	GRECT area;
654 	OBJECT *obj;
655 
656 	NSLOG(netsurf, INFO, "rootwin %p", rootwin);
657 
658 	gw = rootwin->active_gui_window;
659 	bw = gw->browser->bw;
660 	obj = toolbar_get_form(rootwin->toolbar);
661 
662 	if (gw->search == NULL) {
663 		gw->search = nsatari_search_session_create(obj, gw);
664 	}
665 
666 	toolbar_set_visible(rootwin->toolbar, TOOLBAR_AREA_SEARCH, true);
667 	window_get_grect(rootwin, BROWSER_AREA_TOOLBAR, &area);
668 	gemtk_wm_set_toolbar_size(rootwin->win, area.g_h);
669 	window_get_grect(rootwin, BROWSER_AREA_SEARCH, &area);
670 	window_schedule_redraw_grect(rootwin, &area);
671 	window_process_redraws(rootwin);
672 	window_set_focus(rootwin, SEARCH_INPUT, NULL);
673 
674 	window_get_grect(rootwin, BROWSER_AREA_CONTENT, &area);
675 	if (reformat) {
676 		browser_window_reformat(bw, false, area.g_w, area.g_h);
677 	}
678 }
679 
window_close_search(ROOTWIN * rootwin)680 void window_close_search(ROOTWIN *rootwin)
681 {
682 	struct browser_window *bw;
683 	struct gui_window *gw;
684 	GRECT area;
685 	//OBJECT *obj;
686 
687 
688 	gw = rootwin->active_gui_window;
689 	bw = gw->browser->bw;
690 	//obj = gemtk_obj_get_tree(TOOLBAR);
691 
692 	if (gw->search != NULL) {
693 		nsatari_search_session_destroy(gw->search);
694 		gw->search = NULL;
695 	}
696 
697 	toolbar_set_visible(rootwin->toolbar, TOOLBAR_AREA_SEARCH, false);
698 	window_get_grect(rootwin, BROWSER_AREA_TOOLBAR, &area);
699 	gemtk_wm_set_toolbar_size(rootwin->win, area.g_h);
700 	window_get_grect(rootwin, BROWSER_AREA_CONTENT, &area);
701 	browser_window_reformat(bw, false, area.g_w, area.g_h);
702 }
703 
704 /**
705  * Redraw the favicon
706 */
window_redraw_favicon(ROOTWIN * rootwin,GRECT * clip_ro)707 void window_redraw_favicon(ROOTWIN *rootwin, GRECT *clip_ro)
708 {
709     GRECT work, visible, clip;
710 
711     assert(rootwin);
712 
713     //printf("window_redraw_favicon: root: %p, win: %p\n", rootwin, rootwin->win);
714 
715     gemtk_wm_clear(rootwin->win);
716     gemtk_wm_get_grect(rootwin->win, GEMTK_WM_AREA_WORK, &work);
717 
718     if (clip_ro == NULL) {
719         clip = work;
720     } else {
721     	clip = *clip_ro;
722         if(!rc_intersect(&work, &clip)) {
723             return;
724         }
725     }
726 
727     //dbg_grect("favicon redrw area", clip);
728 	//dbg_grect("favicon work area", &work);
729 
730     if (rootwin->icon == NULL) {
731         //printf("window_redraw_favicon OBJCTREE\n");
732 
733         OBJECT * tree = gemtk_obj_get_tree(ICONIFY);
734         tree->ob_x = work.g_x;
735         tree->ob_y = work.g_y;
736         tree->ob_width = work.g_w;
737         tree->ob_height = work.g_h;
738 
739         wind_get_grect(rootwin->aes_handle, WF_FIRSTXYWH, &visible);
740 		while (visible.g_h > 0 && visible.g_w > 0) {
741 
742 			if (rc_intersect(&clip, &visible)) {
743 				//dbg_grect("redraw vis area", &visible);
744 				objc_draw(tree, 0, 8, visible.g_x, visible.g_y, visible.g_w,
745 							visible.g_h);
746 			} else {
747 				//dbg_grect("redraw vis area outside", &visible);
748 			}
749 
750 			wind_get_grect(rootwin->aes_handle, WF_NEXTXYWH, &visible);
751 		}
752 
753     } else {
754         //printf("window_redraw_favicon image %p\n", rootwin->icon);
755         VdiHdl plot_vdi_handle = plot_get_vdi_handle();
756         short pxy[4];
757         int xoff=0;
758 
759         if (work.g_w > work.g_h) {
760             xoff = ((work.g_w-work.g_h)/2);
761             work.g_w = work.g_h;
762         }
763         plot_set_dimensions(&rootwin_rdrw_ctx,
764 			    work.g_x+xoff,
765 			    work.g_y,
766 			    work.g_w,
767 			    work.g_h);
768 
769 		wind_get_grect(rootwin->aes_handle, WF_FIRSTXYWH, &visible);
770 		while (visible.g_h > 0 && visible.g_w > 0) {
771 
772 			if (rc_intersect(&clip, &visible)) {
773 
774 				//dbg_grect("redraw vis area", &visible);
775 
776 				// Manually clip drawing region:
777 				pxy[0] = visible.g_x;
778 				pxy[1] = visible.g_y;
779 				pxy[2] = pxy[0] + visible.g_w-1;
780 				pxy[3] = pxy[1] + visible.g_h-1;
781 				vs_clip(plot_vdi_handle, 1, (short*)&pxy);
782 				//dbg_pxy("vdi clip", (short*)&pxy);
783 
784 				rootwin_rdrw_ctx.plot->bitmap(&rootwin_rdrw_ctx,
785 							      rootwin->icon,
786 							      0,
787 							      0,
788 							      work.g_w,
789 							      work.g_h,
790 							      0xffffff,
791 							      0);
792 			} else {
793 				//dbg_grect("redraw vis area outside", &visible);
794 			}
795 
796 			wind_get_grect(rootwin->aes_handle, WF_NEXTXYWH, &visible);
797 		}
798     }
799 }
800 
801 /***
802 *   Schedule an redraw area, redraw requests during redraw are
803 *   not optimized (merged) into other areas, so that the redraw
804 *   functions can spot the change.
805 *
806 */
window_schedule_redraw_grect(ROOTWIN * rootwin,GRECT * area)807 void window_schedule_redraw_grect(ROOTWIN *rootwin, GRECT *area)
808 {
809     GRECT work;
810 
811 
812     //dbg_grect("window_schedule_redraw_grect input ", area);
813 
814     gemtk_wm_get_grect(rootwin->win, GEMTK_WM_AREA_WORK, &work);
815     if(!rc_intersect(area, &work))
816         return;
817 
818     //dbg_grect("window_schedule_redraw_grect intersection ", &work);
819 
820     redraw_slot_schedule_grect(&rootwin->redraw_slots, &work, redraw_active);
821 }
822 
window_redraw_content(ROOTWIN * rootwin,GRECT * content_area,GRECT * clip,struct gemtk_wm_scroll_info_s * slid,struct browser_window * bw)823 static void window_redraw_content(ROOTWIN *rootwin, GRECT *content_area,
824                                   GRECT *clip,
825                                   struct gemtk_wm_scroll_info_s * slid,
826                                   struct browser_window *bw)
827 {
828 
829     struct rect redraw_area;
830     GRECT content_area_rel;
831     float oldscale = 1.0;
832 
833     //dbg_grect("browser redraw, content area", content_area);
834     //dbg_grect("browser redraw, content clip", clip);
835 
836     plot_set_dimensions(&rootwin_rdrw_ctx,
837 			content_area->g_x, content_area->g_y,
838                         content_area->g_w, content_area->g_h);
839     oldscale = plot_set_scale(browser_window_get_scale(rootwin->active_gui_window->browser->bw));
840 
841     /* first, we make the coords relative to the content area: */
842     content_area_rel.g_x = clip->g_x - content_area->g_x;
843     content_area_rel.g_y = clip->g_y - content_area->g_y;
844     content_area_rel.g_w = clip->g_w;
845     content_area_rel.g_h = clip->g_h;
846 
847     if (content_area_rel.g_x < 0) {
848         content_area_rel.g_w += content_area_rel.g_x;
849         content_area_rel.g_x = 0;
850     }
851 
852     if (content_area_rel.g_y < 0) {
853         content_area_rel.g_h += content_area_rel.g_y;
854         content_area_rel.g_y = 0;
855     }
856 
857     //dbg_grect("browser redraw, relative plot coords:", &content_area_rel);
858 
859     redraw_area.x0 = content_area_rel.g_x;
860     redraw_area.y0 = content_area_rel.g_y;
861     redraw_area.x1 = content_area_rel.g_x + content_area_rel.g_w;
862     redraw_area.y1 = content_area_rel.g_y + content_area_rel.g_h;
863 
864     rootwin_rdrw_ctx.plot->clip(&rootwin_rdrw_ctx, &redraw_area);
865 
866     //dbg_rect("rdrw area", &redraw_area);
867 
868     browser_window_redraw( bw, -(slid->x_pos*slid->x_unit_px),
869                            -(slid->y_pos*slid->y_unit_px), &redraw_area, &rootwin_rdrw_ctx);
870 
871     plot_set_scale(oldscale);
872 }
873 
874 
window_place_caret(ROOTWIN * rootwin,short mode,int content_x,int content_y,int h,GRECT * work)875 void window_place_caret(ROOTWIN *rootwin, short mode, int content_x,
876                         int content_y, int h, GRECT *work)
877 {
878     struct s_caret *caret = &rootwin->caret;
879     VdiHdl vh = gemtk_wm_get_vdi_handle(rootwin->win);
880     short pxy[8];
881     GRECT mywork, caret_pos;
882     MFDB screen;
883     int scroll_x, scroll_y;
884     uint16_t *fd_addr;
885     struct gemtk_wm_scroll_info_s *slid;
886     short colors[2] = {G_BLACK, G_WHITE};
887     bool render_required = false;
888 
889     // avoid duplicate draw of the caret:
890     if (mode == 1 &&(caret->state&CARET_STATE_VISIBLE)!=0) {
891         if (caret->dimensions.g_x == content_x
892                 && caret->dimensions.g_y == content_y
893                 && caret->dimensions.g_h == h) {
894             return;
895         }
896     }
897 
898     if(work == NULL) {
899         window_get_grect(rootwin, BROWSER_AREA_CONTENT, &mywork);
900         work = &mywork;
901     }
902     slid = gemtk_wm_get_scroll_info(rootwin->win);
903 
904     scroll_x = slid->x_pos * slid->x_unit_px;
905     scroll_y = slid->y_pos * slid->y_unit_px;
906 
907     init_mfdb(0, 1, h, 0, &screen);
908 
909     // enable clipping:
910     pxy[0] = work->g_x;
911     pxy[1] = work->g_y;
912     pxy[2] = pxy[0] + work->g_w - 1;
913     pxy[3] = pxy[1] + work->g_h - 1;
914     vs_clip(vh, 1, pxy);
915 
916     // when the caret is visible, undraw it:
917     if (caret->symbol.fd_addr != NULL
918             && (caret->state&CARET_STATE_VISIBLE)!=0) {
919 
920         caret_pos.g_x = work->g_x + (caret->dimensions.g_x - scroll_x);
921         caret_pos.g_y = work->g_y + (caret->dimensions.g_y - scroll_y);
922         caret_pos.g_w = caret->dimensions.g_w;
923         caret_pos.g_h = caret->dimensions.g_h;
924 
925         if (rc_intersect(work, &caret_pos)) {
926 
927             pxy[0] = 0;
928             pxy[1] = 0;
929             pxy[2] = caret->dimensions.g_w-1;
930             pxy[3] = caret->dimensions.g_h-1;
931 
932             pxy[4] = caret_pos.g_x;
933             pxy[5] = caret_pos.g_y;
934             pxy[6] = pxy[4] + caret_pos.g_w-1;
935             pxy[7] = pxy[5] + caret_pos.g_h-1;
936 
937             vrt_cpyfm(vh, MD_XOR, pxy, &caret->symbol, &screen, colors);
938         }
939     }
940     if (mode == 0) {
941         // update state:
942         caret->state &= ~CARET_STATE_VISIBLE;
943         goto exit;
944     }
945 
946     // when the caret isn't allocated, create it:
947     if (caret->symbol.fd_addr == NULL) {
948         caret->fd_size = init_mfdb(1, 16, h, MFDB_FLAG_ZEROMEM,
949                                    &caret->symbol);
950         render_required = true;
951     } else {
952         // the caret may need more memory:
953         if (caret->dimensions.g_h < h) {
954             caret->fd_size = init_mfdb(1, 16, h, MFDB_FLAG_NOALLOC,
955                                        &caret->symbol);
956             realloc(caret->symbol.fd_addr, caret->fd_size);
957             render_required = true;
958         }
959     }
960 
961     // set new caret position:
962     caret->dimensions.g_x = content_x;
963     caret->dimensions.g_y = content_y;
964     caret->dimensions.g_w = 1;
965     caret->dimensions.g_h = h;
966 
967     // draw the caret into the mfdb buffer:
968     if (render_required) {
969         int i;
970 
971         assert(caret->symbol.fd_nplanes == 1);
972         assert(caret->symbol.fd_w == 16);
973 
974         // draw an vertical line into the mfdb buffer
975         fd_addr = (uint16_t*)caret->symbol.fd_addr;
976         for(i = 0; i<caret->symbol.fd_h; i++) {
977             fd_addr[i] = 0xFFFF;
978         }
979     }
980 
981     // convert content coords to screen coords:
982 
983     caret_pos.g_x = work->g_x + (content_x - scroll_x);
984     caret_pos.g_y = work->g_y + (content_y - scroll_y);
985     caret_pos.g_w = caret->dimensions.g_w;
986     caret_pos.g_h = caret->dimensions.g_h;
987 
988     if (rc_intersect(work, &caret_pos) && redraw_active == false) {
989 
990         pxy[0] = 0;
991         pxy[1] = 0;
992         pxy[2] = caret->dimensions.g_w-1;
993         pxy[3] = caret->dimensions.g_h-1;
994 
995         pxy[4] = caret_pos.g_x;
996         pxy[5] = caret_pos.g_y;
997         pxy[6] = pxy[4] + caret_pos.g_w-1;
998         pxy[7] = pxy[5] + caret_pos.g_h-1;
999 
1000         //dbg_pxy("caret screen coords (md_repl)", &pxy[4]);
1001 
1002         // TODO: walk rectangle list (use MD_REPLACE then)
1003         // draw caret to screen coords:
1004         vrt_cpyfm(vh, /*MD_REPLACE*/ MD_XOR, pxy, &caret->symbol, &screen, colors);
1005 
1006         // update state:
1007         caret->state |= CARET_STATE_VISIBLE;
1008     }
1009 
1010 exit:
1011     // disable clipping:
1012     vs_clip(gemtk_wm_get_vdi_handle(rootwin->win), 0, pxy);
1013 }
1014 
window_process_redraws(ROOTWIN * rootwin)1015 void window_process_redraws(ROOTWIN * rootwin)
1016 {
1017     GRECT visible_ro, tb_area, content_area;
1018     short i;
1019     short scroll_x=0, scroll_y=0;
1020     bool caret_rdrw_required = false;
1021     struct gemtk_wm_scroll_info_s *slid =NULL;
1022     int caret_h = 0;
1023     struct s_caret *caret = &rootwin->caret;
1024 
1025     redraw_active = true;
1026 
1027     window_get_grect(rootwin, BROWSER_AREA_TOOLBAR, &tb_area);
1028     //gemtk_wm_set_toolbar_size(rootwin->win, tb_area.g_h);
1029     window_get_grect(rootwin, BROWSER_AREA_CONTENT, &content_area);
1030 
1031     //dbg_grect("content area", &content_area);
1032     //dbg_grect("window_process_redraws toolbar area", &tb_area);
1033 
1034     while(plot_lock() == false);
1035 
1036     if (((rootwin->caret.state & CARET_STATE_ENABLED)!=0)
1037             && rootwin->caret.dimensions.g_h > 0) {
1038         // hide caret:
1039         window_place_caret(rootwin, 0, -1, -1, -1, &content_area);
1040     }
1041 /*
1042     short pxy_clip[4];
1043     pxy_clip[0] = tb_area.g_x;
1044     pxy_clip[0] = tb_area.g_y;
1045     pxy_clip[0] = pxy_clip[0] + tb_area.g_w + content_area.g_w - 1;
1046     pxy_clip[0] = pxy_clip[1] + tb_area.g_h + content_area.g_h - 1;
1047     vs_clip(gemtk_wm_get_vdi_handle(rootwin->win), 1, pxy_clip);
1048 	//gemtk_wm_clear(rootwin->win);
1049 */
1050     wind_get_grect(rootwin->aes_handle, WF_FIRSTXYWH, &visible_ro);
1051     while (visible_ro.g_w > 0 && visible_ro.g_h > 0) {
1052         plot_set_abs_clipping(&visible_ro);
1053 
1054     	//dbg_grect("visible ", &visible_ro);
1055 
1056         // TODO: optimze the rectangle list -
1057         // remove rectangles which were completly inside the visible area.
1058         // that way we don't have to loop over again...
1059         for(i=0; i<rootwin->redraw_slots.areas_used; i++) {
1060 
1061             GRECT rdrw_area_ro = {
1062                 rootwin->redraw_slots.areas[i].x0,
1063                 rootwin->redraw_slots.areas[i].y0,
1064                 rootwin->redraw_slots.areas[i].x1 -
1065                 rootwin->redraw_slots.areas[i].x0,
1066                 rootwin->redraw_slots.areas[i].y1 -
1067                 rootwin->redraw_slots.areas[i].y0
1068             };
1069 
1070             if (!rc_intersect(&visible_ro, &rdrw_area_ro)) {
1071 				continue;
1072             }
1073             GRECT rdrw_area = rdrw_area_ro;
1074 
1075             if (rc_intersect(&tb_area, &rdrw_area)) {
1076 				toolbar_redraw(rootwin->toolbar, &rdrw_area);
1077             }
1078 
1079             rdrw_area = rdrw_area_ro;
1080             if (rc_intersect(&content_area, &rdrw_area)) {
1081 
1082                 if(slid == NULL) {
1083                     slid = gemtk_wm_get_scroll_info(rootwin->win);
1084 
1085                     scroll_x = slid->x_pos * slid->x_unit_px;
1086                     scroll_y = slid->y_pos * slid->y_unit_px;
1087                 }
1088 
1089                 window_redraw_content(rootwin, &content_area, &rdrw_area,
1090                                       slid,
1091                                       rootwin->active_gui_window->browser->bw);
1092                 if (((rootwin->caret.state & CARET_STATE_ENABLED)!=0)) {
1093 
1094                     GRECT caret_pos;
1095 
1096                     caret_pos.g_x = content_area.g_x +
1097                                     (caret->dimensions.g_x - scroll_x);
1098                     caret_pos.g_y = content_area.g_y +
1099                                     (caret->dimensions.g_y - scroll_y);
1100                     caret_pos.g_w = caret->dimensions.g_w;
1101                     caret_pos.g_h = caret->dimensions.g_h;
1102 
1103                     if (gemtk_rc_intersect_ro(&caret_pos, &content_area)) {
1104                         caret_rdrw_required = true;
1105                     }
1106                 }
1107 
1108             }
1109         }
1110         wind_get_grect(rootwin->aes_handle, WF_NEXTXYWH, &visible_ro);
1111     }
1112 
1113 
1114     // disable clipping:
1115     //vs_clip(gemtk_wm_get_vdi_handle(rootwin->win), 0, pxy_clip);
1116 
1117     if (caret_rdrw_required && ((rootwin->caret.state & CARET_STATE_ENABLED)!=0)) {
1118 
1119         // force redraw of caret:
1120         caret_h = rootwin->caret.dimensions.g_h;
1121         rootwin->caret.dimensions.g_h = 0;
1122         redraw_active = false;
1123         window_place_caret(rootwin, 1, rootwin->caret.dimensions.g_x,
1124                            rootwin->caret.dimensions.g_y,
1125                            caret_h, &content_area);
1126     }
1127 
1128     rootwin->redraw_slots.areas_used = 0;
1129     redraw_active = false;
1130 
1131     plot_unlock();
1132 }
1133 
1134 
1135 /* -------------------------------------------------------------------------- */
1136 /* Event Handlers:                                                            */
1137 /* -------------------------------------------------------------------------- */
on_content_mouse_move(ROOTWIN * rootwin,GRECT * content_area)1138 static void on_content_mouse_move(ROOTWIN *rootwin, GRECT *content_area)
1139 {
1140     int mx, my, sx, sy;
1141     struct gemtk_wm_scroll_info_s *slid;
1142     struct gui_window *gw;
1143     struct browser_window *bw;
1144 
1145     // make relative mouse coords:
1146     mx = aes_event_out.emo_mouse.p_x - content_area->g_x;
1147     my = aes_event_out.emo_mouse.p_y - content_area->g_y;
1148 
1149     slid = gemtk_wm_get_scroll_info(rootwin->win);
1150     gw = window_get_active_gui_window(rootwin);
1151     bw = gw->browser->bw;
1152 
1153     // calculate scroll pos. in pixel:
1154     sx = slid->x_pos * slid->x_unit_px;
1155     sy = slid->y_pos * slid->y_unit_px;
1156 
1157     browser_window_mouse_track(bw, 0, mx + sx, my + sy);
1158 }
1159 
on_content_mouse_click(ROOTWIN * rootwin)1160 static void on_content_mouse_click(ROOTWIN *rootwin)
1161 {
1162     short dummy, mbut, mx, my;
1163     GRECT cwork;
1164     browser_mouse_state bmstate = 0;
1165     struct gui_window *gw;
1166     struct gemtk_wm_scroll_info_s *slid;
1167 
1168     gw = window_get_active_gui_window(rootwin);
1169     if(input_window != gw) {
1170         gui_set_input_gui_window(gw);
1171     }
1172 
1173     window_set_focus(gw->root, BROWSER, (void*)gw->browser );
1174     window_get_grect(gw->root, BROWSER_AREA_CONTENT, &cwork);
1175 
1176     /* convert screen coords to component coords: */
1177     mx = aes_event_out.emo_mouse.p_x - cwork.g_x;
1178     my = aes_event_out.emo_mouse.p_y - cwork.g_y;
1179     //printf("content click at %d,%d\n", mx, my);
1180 
1181     /* Translate GEM key state to netsurf mouse modifier */
1182     if ( aes_event_out.emo_kmeta & (K_RSHIFT | K_LSHIFT)) {
1183         bmstate |= BROWSER_MOUSE_MOD_1;
1184     } else {
1185         bmstate &= ~(BROWSER_MOUSE_MOD_1);
1186     }
1187     if ( (aes_event_out.emo_kmeta & K_CTRL) ) {
1188         bmstate |= BROWSER_MOUSE_MOD_2;
1189     } else {
1190         bmstate &= ~(BROWSER_MOUSE_MOD_2);
1191     }
1192     if ( (aes_event_out.emo_kmeta & K_ALT) ) {
1193         bmstate |= BROWSER_MOUSE_MOD_3;
1194     } else {
1195         bmstate &= ~(BROWSER_MOUSE_MOD_3);
1196     }
1197 
1198     /* convert component coords to scrolled content coords: */
1199     slid = gemtk_wm_get_scroll_info(rootwin->win);
1200     int sx_origin = mx;
1201     int sy_origin = my;
1202 
1203     short rel_cur_x, rel_cur_y;
1204     short prev_x=sx_origin, prev_y=sy_origin;
1205     bool dragmode = false;
1206 
1207     /* Detect left mouse button state and compare with event state: */
1208     graf_mkstate(&rel_cur_x, &rel_cur_y, &mbut, &dummy);
1209     if( (mbut & 1) && (aes_event_out.emo_mbutton & 1) ) {
1210         /* Mouse still pressed, report drag */
1211         rel_cur_x = (rel_cur_x - cwork.g_x);
1212         rel_cur_y = (rel_cur_y - cwork.g_y);
1213         browser_window_mouse_click( gw->browser->bw,
1214                                     BROWSER_MOUSE_DRAG_ON|BROWSER_MOUSE_DRAG_1,
1215                                     rel_cur_x + slid->x_pos * slid->x_unit_px,
1216                                     rel_cur_y + slid->y_pos * slid->y_unit_px);
1217         do {
1218             // only consider movements of 5px or more as drag...:
1219             if( abs(prev_x-rel_cur_x) > 5 || abs(prev_y-rel_cur_y) > 5 ) {
1220                 browser_window_mouse_track( gw->browser->bw,
1221                                             BROWSER_MOUSE_DRAG_ON|BROWSER_MOUSE_DRAG_1,
1222                                             rel_cur_x + slid->x_pos * slid->x_unit_px,
1223                                             rel_cur_y + slid->y_pos * slid->y_unit_px);
1224                 prev_x = rel_cur_x;
1225                 prev_y = rel_cur_y;
1226                 dragmode = true;
1227             } else {
1228                 if( dragmode == false ) {
1229                     browser_window_mouse_track( gw->browser->bw,BROWSER_MOUSE_PRESS_1,
1230                                                 rel_cur_x + slid->x_pos * slid->x_unit_px,
1231                                                 rel_cur_y + slid->y_pos * slid->y_unit_px);
1232                 }
1233             }
1234 
1235             // we may need to process scrolling:
1236             // TODO: this doesn't work, because gemtk schedules redraw via
1237             // AES window messages but we do not process them right here...
1238             if (rootwin->redraw_slots.areas_used > 0) {
1239                 window_process_redraws(rootwin);
1240             }
1241             evnt_timer(150);
1242 
1243             graf_mkstate(&rel_cur_x, &rel_cur_y, &mbut, &dummy);
1244             rel_cur_x = (rel_cur_x - cwork.g_x);
1245             rel_cur_y = (rel_cur_y - cwork.g_y);
1246         } while( mbut & 1 );
1247         browser_window_mouse_track(gw->browser->bw, 0,
1248                                    rel_cur_x + slid->x_pos * slid->x_unit_px,
1249                                    rel_cur_y + slid->y_pos * slid->y_unit_px);
1250     } else {
1251         /* Right button pressed? */
1252         if ((aes_event_out.emo_mbutton & 2 ) ) {
1253             context_popup(gw, aes_event_out.emo_mouse.p_x,
1254                           aes_event_out.emo_mouse.p_y);
1255         } else {
1256             browser_window_mouse_click(gw->browser->bw,
1257                                        bmstate|BROWSER_MOUSE_PRESS_1,
1258                                        sx_origin + slid->x_pos * slid->x_unit_px,
1259                                        sy_origin + slid->y_pos * slid->y_unit_px);
1260             browser_window_mouse_click(gw->browser->bw,
1261                                        bmstate|BROWSER_MOUSE_CLICK_1,
1262                                        sx_origin + slid->x_pos * slid->x_unit_px,
1263                                        sy_origin + slid->y_pos * slid->y_unit_px);
1264         }
1265     }
1266     if (rootwin->redraw_slots.areas_used > 0) {
1267         window_process_redraws(rootwin);
1268     }
1269 }
1270 
1271 /*
1272 	Report keypress to browser component.
1273 	parameter:
1274 		- unsigned short nkc ( CFLIB normalised key code )
1275 */
on_content_keypress(struct gui_window * gw,unsigned short nkc)1276 static bool on_content_keypress(struct gui_window *gw, unsigned short nkc)
1277 {
1278     bool r = false;
1279     unsigned char ascii = (nkc & 0xFF);
1280     long ucs4;
1281     long ik = nkc_to_input_key( nkc, &ucs4 );
1282 
1283     // pass event to specific control?
1284 
1285     if (ik == 0) {
1286         if (ascii >= 9) {
1287             r = browser_window_key_press(gw->browser->bw, ucs4);
1288         }
1289     } else {
1290         r = browser_window_key_press(gw->browser->bw, ik);
1291         if (r == false) {
1292 
1293             GRECT g;
1294             GUIWIN * w = gw->root->win;
1295             window_get_grect(gw->root, BROWSER_AREA_CONTENT, &g);
1296 
1297             struct gemtk_wm_scroll_info_s *slid = gemtk_wm_get_scroll_info(w);
1298 
1299             switch( ik ) {
1300             case NS_KEY_LINE_START:
1301                 gemtk_wm_scroll(w, GEMTK_WM_HSLIDER, -(g.g_w/slid->x_unit_px),
1302                               false);
1303 				r = true;
1304                 break;
1305 
1306             case NS_KEY_LINE_END:
1307                 gemtk_wm_scroll(w, GEMTK_WM_HSLIDER, (g.g_w/slid->x_unit_px),
1308                               false);
1309 				r = true;
1310                 break;
1311 
1312             case NS_KEY_PAGE_UP:
1313                 gemtk_wm_scroll(w, GEMTK_WM_VSLIDER, -(g.g_h/slid->y_unit_px),
1314                               false);
1315 				r = true;
1316                 break;
1317 
1318             case NS_KEY_PAGE_DOWN:
1319                 gemtk_wm_scroll(w, GEMTK_WM_VSLIDER, (g.g_h/slid->y_unit_px),
1320                               false);
1321 				r = true;
1322                 break;
1323 
1324             case NS_KEY_RIGHT:
1325                 gemtk_wm_scroll(w, GEMTK_WM_HSLIDER, -1, false);
1326 				r = true;
1327                 break;
1328 
1329             case NS_KEY_LEFT:
1330                 gemtk_wm_scroll(w, GEMTK_WM_HSLIDER, 1, false);
1331 				r = true;
1332                 break;
1333 
1334             case NS_KEY_UP:
1335                 gemtk_wm_scroll(w, GEMTK_WM_VSLIDER, -1, false);
1336 				r = true;
1337                 break;
1338 
1339             case NS_KEY_DOWN:
1340                 gemtk_wm_scroll(w, GEMTK_WM_VSLIDER, 1, false);
1341                 r = true;
1342                 break;
1343 
1344 			case NS_KEY_TEXT_START:
1345 				window_scroll_by(gw->root, 0, 0);
1346 				r = true;
1347 				break;
1348 
1349             default:
1350                 break;
1351             }
1352             gemtk_wm_update_slider(w, GEMTK_WM_VSLIDER|GEMTK_WM_HSLIDER);
1353         }
1354     }
1355 
1356     return(r);
1357 }
1358 
on_window_key_input(ROOTWIN * rootwin,unsigned short nkc)1359 static short on_window_key_input(ROOTWIN *rootwin, unsigned short nkc)
1360 {
1361     bool done = false;
1362     struct gui_window * gw = window_get_active_gui_window(rootwin);
1363 
1364     if( gw == NULL )
1365         return(false);
1366 
1367     if(window_url_widget_has_focus((void*)gw->root)) {
1368         /* make sure we report for the root window and report...: */
1369         done = toolbar_key_input(gw->root->toolbar, nkc);
1370     }  else  {
1371         if( window_widget_has_focus(input_window->root, BROWSER,
1372 			(void*)input_window->browser)) {
1373 			done = on_content_keypress(input_window, nkc);
1374 		}
1375 		else if(window_widget_has_focus(input_window->root, SEARCH_INPUT, NULL)) {
1376 			OBJECT * obj;
1377 				obj = toolbar_get_form(input_window->root->toolbar);
1378 				obj[TOOLBAR_BT_SEARCH_FWD].ob_state &= ~OS_DISABLED;
1379 				obj[TOOLBAR_BT_SEARCH_BACK].ob_state &= ~OS_DISABLED;
1380 				window_schedule_redraw_grect(input_window->root,
1381 							gemtk_obj_screen_rect(obj, TOOLBAR_BT_SEARCH_FWD));
1382 				window_schedule_redraw_grect(input_window->root,
1383 							gemtk_obj_screen_rect(obj, TOOLBAR_BT_SEARCH_BACK));
1384 		}
1385     }
1386     return((done==true) ? 1 : 0);
1387 }
1388 
1389 
on_redraw(ROOTWIN * rootwin,short msg[8])1390 static void on_redraw(ROOTWIN *rootwin, short msg[8])
1391 {
1392     GRECT clip = {msg[4], msg[5], msg[6], msg[7]};
1393 
1394     //dbg_grect("on_redraw", &clip);
1395 
1396     if(gemtk_wm_get_state(rootwin->win) & GEMTK_WM_STATUS_ICONIFIED) {
1397         // TODO: remove asignment:
1398         window_redraw_favicon(rootwin, NULL);
1399     } else {
1400         window_schedule_redraw_grect(rootwin, &clip);
1401     }
1402 }
1403 
on_resized(ROOTWIN * rootwin)1404 static void on_resized(ROOTWIN *rootwin)
1405 {
1406     GRECT g, work;
1407     struct gui_window *gw;
1408 
1409     gw = window_get_active_gui_window(rootwin);
1410 
1411     //printf("resized...\n");
1412 
1413     assert(gw != NULL);
1414 
1415     if(gw == NULL)
1416         return;
1417 
1418     wind_get_grect(rootwin->aes_handle, WF_CURRXYWH, &g);
1419 	gemtk_wm_get_grect(rootwin->win, GEMTK_WM_AREA_WORK, &work);
1420 
1421     if (rootwin->loc.g_w != g.g_w || rootwin->loc.g_h != g.g_h) {
1422 
1423 		/* resized */
1424     	toolbar_set_width(rootwin->toolbar, work.g_w);
1425 
1426         if ( browser_window_has_content(gw->browser->bw) ) {
1427             browser_window_reformat(gw->browser->bw, true, work.g_w, work.g_h);
1428         }
1429     }
1430     if (rootwin->loc.g_x != g.g_x || rootwin->loc.g_y != g.g_y) {
1431         /* moved */
1432         toolbar_set_origin(rootwin->toolbar, work.g_x, work.g_y);
1433     }
1434 
1435     rootwin->loc = g;
1436 }
1437 
on_file_dropped(ROOTWIN * rootwin,short msg[8])1438 static void on_file_dropped(ROOTWIN *rootwin, short msg[8])
1439 {
1440     char file[DD_NAMEMAX];
1441     char name[DD_NAMEMAX];
1442     char *buff=NULL;
1443     int dd_hdl;
1444     int dd_msg; /* pipe-handle */
1445     long size;
1446     char ext[32];
1447     short mx,my,bmstat,mkstat;
1448     struct gui_window *gw;
1449 
1450     graf_mkstate(&mx, &my, &bmstat, &mkstat);
1451 
1452     gw = window_get_active_gui_window(rootwin);
1453 
1454     if( gw == NULL )
1455         return;
1456 
1457     if(gemtk_wm_get_state(rootwin->win) & GEMTK_WM_STATUS_ICONIFIED)
1458         return;
1459 
1460     dd_hdl = gemtk_dd_open( msg[7], DD_OK);
1461     if( dd_hdl<0)
1462         return;	/* pipe not open */
1463     memset( ext, 0, 32);
1464     strcpy( ext, "ARGS");
1465     dd_msg = gemtk_dd_sexts( dd_hdl, ext);
1466     if( dd_msg<0)
1467         goto error;
1468     dd_msg = gemtk_dd_rtry( dd_hdl, (char*)&name[0], (char*)&file[0], (char*)&ext[0], &size);
1469     if( size+1 >= PATH_MAX )
1470         goto error;
1471     if( !strncmp( ext, "ARGS", 4) && dd_msg > 0) {
1472         gemtk_dd_reply(dd_hdl, DD_OK);
1473         buff = (char*)malloc(sizeof(char)*(size+1));
1474         if (buff != NULL) {
1475             if (Fread(dd_hdl, size, buff ) == size) {
1476 
1477                 int sx, sy;
1478                 bool processed = false;
1479                 GRECT content_area;
1480 
1481                 buff[size] = 0;
1482 
1483                 NSLOG(netsurf, INFO,
1484                       "file: %s, ext: %s, size: %ld dropped at: %d,%d\n",
1485                       (char *)buff,
1486                       (char *)&ext,
1487                       size,
1488                       mx,
1489                       my);
1490 
1491                 gui_window_get_scroll(gw, &sx, &sy);
1492 
1493                 window_get_grect(rootwin, BROWSER_AREA_CONTENT, &content_area);
1494                 mx = mx - content_area.g_x;
1495                 my = my - content_area.g_y;
1496                 if((mx < 0 || mx > content_area.g_w)
1497                         || (my < 0 || my > content_area.g_h))
1498                     return;
1499 
1500                 processed = browser_window_drop_file_at_point(gw->browser->bw,
1501                                                               mx+sx, my+sy,
1502                                                               NULL);
1503                 if(processed == true) {
1504                     nserror ret;
1505                     char *utf8_fn;
1506 
1507                     ret = utf8_from_local_encoding(buff, 0, &utf8_fn);
1508                     if (ret != NSERROR_OK) {
1509                         free(buff);
1510                         /* A bad encoding should never happen */
1511                         NSLOG(netsurf, INFO,
1512                               "utf8_from_local_encoding failed");
1513                         assert(ret != NSERROR_BAD_ENCODING);
1514                         /* no memory */
1515                         goto error;
1516                     }
1517                     processed = browser_window_drop_file_at_point(gw->browser->bw,
1518                                                                   mx+sx, my+sy,
1519                                                                   utf8_fn);
1520                     free(utf8_fn);
1521                 }
1522 
1523                 if(processed == false) {
1524                     // TODO: use localized string:
1525                     if(gemtk_msg_box_show(GEMTK_MSG_BOX_CONFIRM, "Open File?") > 0) {
1526                         nsurl * ns_url = NULL;
1527                         char * tmp_url = local_file_to_url(buff);
1528                         if ((tmp_url  != NULL)
1529                             && nsurl_create(tmp_url, &ns_url) == NSERROR_OK) {
1530                             browser_window_navigate(gw->browser->bw, ns_url, NULL,
1531                                 BW_NAVIGATE_HISTORY,
1532                                 NULL, NULL, NULL);
1533                             nsurl_unref(ns_url);
1534                         }
1535                     }
1536                 }
1537             }
1538         }
1539     }
1540 error:
1541     if (buff) {
1542         free(buff);
1543     }
1544     gemtk_dd_close( dd_hdl);
1545 }
1546 
toolbar_redraw_cb(GUIWIN * win,uint16_t msg,GRECT * clip)1547 static void	toolbar_redraw_cb(GUIWIN *win, uint16_t msg, GRECT *clip)
1548 {
1549 	struct rootwin_data_s * ud;
1550 
1551 	if (msg != WM_REDRAW) {
1552 		ud = gemtk_wm_get_user_data(win);
1553 
1554 		assert(ud);
1555 
1556 		toolbar_redraw(ud->rootwin->toolbar, clip);
1557 	}
1558 }
1559