void nsbeos_window_expose_event(BView *view, gui_window *g, BMessage *message) { BRect updateRect; hlcache_handle *c; float scale = g->bw->scale; struct rect clip; struct redraw_context ctx = { true, true, &nsbeos_plotters }; assert(g); assert(g->bw); struct gui_window *z; for (z = window_list; z && z != g; z = z->next) continue; assert(z); assert(g->view == view); // we'll be resizing = reflowing = redrawing everything anyway... if (g->pending_resizes > 1) return; if (message->FindRect("rect", &updateRect) < B_OK) return; c = g->bw->current_content; if (c == NULL) return; if (!view->LockLooper()) return; nsbeos_current_gc_set(view); if (view->Window()) view->Window()->BeginViewTransaction(); clip.x0 = (int)updateRect.left; clip.y0 = (int)updateRect.top; clip.x1 = (int)updateRect.right + 1; clip.y1 = (int)updateRect.bottom + 1; browser_window_redraw(g->bw, 0, 0, &clip, &ctx); if (g->careth != 0) nsbeos_plot_caret(g->caretx, g->carety, g->careth); if (view->Window()) view->Window()->EndViewTransaction(); // reset clipping just in case view->ConstrainClippingRegion(NULL); nsbeos_current_gc_set(NULL); view->UnlockLooper(); }
static void browser_redraw_content( struct gui_window * gw, int xoff, int yoff, struct rect * area ) { CMP_BROWSER b = gw->browser; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &atari_plotters }; LOG(("%s : %d,%d - %d,%d\n", b->bw->name, area->x0, area->y0, area->x1, area->y1 )); browser_window_redraw( b->bw, -b->scroll.current.x, -b->scroll.current.y, area, &ctx ); } /* area: the browser canvas */ void browser_restore_caret_background( struct gui_window * gw, LGRECT * area) { CMP_BROWSER b = gw->browser; LGRECT rect; if( area == NULL ){ browser_get_rect( gw, BR_CONTENT, &rect ); area = ▭ } /* This call restores the background and releases the memory: */ // TODO: only release memory/clear flag when the caret is not clipped. // TODO: apply clipping. w_put_bkgr( &app, area->g_x-b->scroll.current.x+b->caret.current.g_x, area->g_y-b->scroll.current.y+b->caret.current.g_y, gw->browser->caret.current.g_w, gw->browser->caret.current.g_h, &gw->browser->caret.background ); gw->browser->caret.background.fd_addr = NULL; }
static gboolean nsgtk_window_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data) { struct gui_window *gw = data; struct gui_window *z; struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &nsgtk_plotters }; double x1; double y1; double x2; double y2; assert(gw); assert(gw->bw); for (z = window_list; z && z != gw; z = z->next) continue; assert(z); assert(GTK_WIDGET(gw->layout) == widget); current_widget = (GtkWidget *)gw->layout; current_cr = cr; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); clip.x0 = x1; clip.y0 = y1; clip.x1 = x2; clip.y1 = y2; browser_window_redraw(gw->bw, 0, 0, &clip, &ctx); if (gw->careth != 0) { nsgtk_plot_caret(gw->caretx, gw->carety, gw->careth); } current_widget = NULL; return FALSE; } #else static gboolean nsgtk_window_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { struct gui_window *gw = data; struct gui_window *z; struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &nsgtk_plotters }; assert(gw); assert(gw->bw); for (z = window_list; z && z != gw; z = z->next) continue; assert(z); assert(GTK_WIDGET(gw->layout) == widget); current_widget = (GtkWidget *)gw->layout; current_cr = gdk_cairo_create(nsgtk_layout_get_bin_window(gw->layout)); clip.x0 = event->area.x; clip.y0 = event->area.y; clip.x1 = event->area.x + event->area.width; clip.y1 = event->area.y + event->area.height; browser_window_redraw(gw->bw, 0, 0, &clip, &ctx); if (gw->careth != 0) { nsgtk_plot_caret(gw->caretx, gw->carety, gw->careth); } cairo_destroy(current_cr); current_widget = NULL; return FALSE; } #endif static gboolean nsgtk_window_motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) { struct gui_window *g = data; bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; if ((abs(event->x - g->last_x) < 5) && (abs(event->y - g->last_y) < 5)) { /* Mouse hasn't moved far enough from press coordinate for this * to be considered a drag. */ return FALSE; } else { /* This is a drag, ensure it's always treated as such, even if * we drag back over the press location */ g->last_x = INT_MIN; g->last_y = INT_MIN; } if (g->mouse.state & BROWSER_MOUSE_PRESS_1) { /* Start button 1 drag */ browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_1, g->mouse.pressed_x, g->mouse.pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_HOLDING_1); g->mouse.state |= BROWSER_MOUSE_DRAG_ON; } else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) { /* Start button 2 drag */ browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_2, g->mouse.pressed_x, g->mouse.pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_HOLDING_2); g->mouse.state |= BROWSER_MOUSE_DRAG_ON; } /* Handle modifiers being removed */ if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) g->mouse.state ^= BROWSER_MOUSE_MOD_1; if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) g->mouse.state ^= BROWSER_MOUSE_MOD_2; browser_window_mouse_track(g->bw, g->mouse.state, event->x / g->bw->scale, event->y / g->bw->scale); return TRUE; } static gboolean nsgtk_window_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct gui_window *g = data; gtk_widget_grab_focus(GTK_WIDGET(g->layout)); gtk_widget_hide(GTK_WIDGET(nsgtk_scaffolding_history_window( g->scaffold)->window)); g->mouse.pressed_x = event->x / g->bw->scale; g->mouse.pressed_y = event->y / g->bw->scale; switch (event->button) { case 1: /* Left button, usually. Pass to core as BUTTON 1. */ g->mouse.state = BROWSER_MOUSE_PRESS_1; break; case 2: /* Middle button, usually. Pass to core as BUTTON 2 */ g->mouse.state = BROWSER_MOUSE_PRESS_2; break; case 3: /* Right button, usually. Action button, context menu. */ browser_window_remove_caret(g->bw); nsgtk_scaffolding_popup_menu(g->scaffold, g->mouse.pressed_x, g->mouse.pressed_y); return TRUE; default: return FALSE; } /* Handle the modifiers too */ if (event->state & GDK_SHIFT_MASK) g->mouse.state |= BROWSER_MOUSE_MOD_1; if (event->state & GDK_CONTROL_MASK) g->mouse.state |= BROWSER_MOUSE_MOD_2; /* Record where we pressed, for use when determining whether to start * a drag in motion notify events. */ g->last_x = event->x; g->last_y = event->y; browser_window_mouse_click(g->bw, g->mouse.state, g->mouse.pressed_x, g->mouse.pressed_y); return TRUE; } static gboolean nsgtk_window_button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct gui_window *g = data; bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; /* If the mouse state is PRESS then we are waiting for a release to emit * a click event, otherwise just reset the state to nothing */ if (g->mouse.state & BROWSER_MOUSE_PRESS_1) g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2); /* Handle modifiers being removed */ if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) g->mouse.state ^= BROWSER_MOUSE_MOD_1; if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) g->mouse.state ^= BROWSER_MOUSE_MOD_2; if (g->mouse.state & (BROWSER_MOUSE_CLICK_1|BROWSER_MOUSE_CLICK_2)) { browser_window_mouse_click(g->bw, g->mouse.state, event->x / g->bw->scale, event->y / g->bw->scale); } else { browser_window_mouse_track(g->bw, 0, event->x / g->bw->scale, event->y / g->bw->scale); } g->mouse.state = 0; return TRUE; } static gboolean nsgtk_window_scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) { struct gui_window *g = data; double value; GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(g->layout); GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(g->layout); GtkAllocation alloc; LOG(("%d", event->direction)); switch (event->direction) { case GDK_SCROLL_LEFT: if (browser_window_scroll_at_point(g->bw, event->x / g->bw->scale, event->y / g->bw->scale, -100, 0) != true) { /* core did not handle event do horizontal scroll */ value = gtk_adjustment_get_value(hscroll) - (nsgtk_adjustment_get_step_increment(hscroll) *2); if (value < nsgtk_adjustment_get_lower(hscroll)) { value = nsgtk_adjustment_get_lower(hscroll); } gtk_adjustment_set_value(hscroll, value); } break; case GDK_SCROLL_UP: if (browser_window_scroll_at_point(g->bw, event->x / g->bw->scale, event->y / g->bw->scale, 0, -100) != true) { /* core did not handle event change vertical * adjustment. */ value = gtk_adjustment_get_value(vscroll) - (nsgtk_adjustment_get_step_increment(vscroll) * 2); if (value < nsgtk_adjustment_get_lower(vscroll)) { value = nsgtk_adjustment_get_lower(vscroll); } gtk_adjustment_set_value(vscroll, value); } break; case GDK_SCROLL_RIGHT: if (browser_window_scroll_at_point(g->bw, event->x / g->bw->scale, event->y / g->bw->scale, 100, 0) != true) { /* core did not handle event change horizontal * adjustment. */ value = gtk_adjustment_get_value(hscroll) + (nsgtk_adjustment_get_step_increment(hscroll) * 2); /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); if (value > nsgtk_adjustment_get_upper(hscroll) - alloc.width) { value = nsgtk_adjustment_get_upper(hscroll) - alloc.width; } gtk_adjustment_set_value(hscroll, value); } break; case GDK_SCROLL_DOWN: if (browser_window_scroll_at_point(g->bw, event->x / g->bw->scale, event->y / g->bw->scale, 0, 100) != true) { /* core did not handle event change vertical * adjustment. */ value = gtk_adjustment_get_value(vscroll) + (nsgtk_adjustment_get_step_increment(vscroll) * 2); /* @todo consider gtk_widget_get_allocated_height */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) { value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; } gtk_adjustment_set_value(vscroll, value); } break; default: break; } return TRUE; } static gboolean nsgtk_window_keypress_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct gui_window *g = data; uint32_t nskey = gtk_gui_gdkkey_to_nskey(event); if (browser_window_key_press(g->bw, nskey)) return TRUE; if ((event->state & 0x7) != 0) return TRUE; double value; GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(g->layout); GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(g->layout); GtkAllocation alloc; /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); switch (event->keyval) { case GDK_KEY(Home): case GDK_KEY(KP_Home): value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(End): case GDK_KEY(KP_End): value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Left): case GDK_KEY(KP_Left): value = gtk_adjustment_get_value(hscroll) - nsgtk_adjustment_get_step_increment(hscroll); if (value < nsgtk_adjustment_get_lower(hscroll)) value = nsgtk_adjustment_get_lower(hscroll); gtk_adjustment_set_value(hscroll, value); break; case GDK_KEY(Up): case GDK_KEY(KP_Up): value = gtk_adjustment_get_value(vscroll) - nsgtk_adjustment_get_step_increment(vscroll); if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Right): case GDK_KEY(KP_Right): value = gtk_adjustment_get_value(hscroll) + nsgtk_adjustment_get_step_increment(hscroll); if (value > nsgtk_adjustment_get_upper(hscroll) - alloc.width) value = nsgtk_adjustment_get_upper(hscroll) - alloc.width; gtk_adjustment_set_value(hscroll, value); break; case GDK_KEY(Down): case GDK_KEY(KP_Down): value = gtk_adjustment_get_value(vscroll) + nsgtk_adjustment_get_step_increment(vscroll); if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Page_Up): case GDK_KEY(KP_Page_Up): value = gtk_adjustment_get_value(vscroll) - nsgtk_adjustment_get_page_increment(vscroll); if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Page_Down): case GDK_KEY(KP_Page_Down): value = gtk_adjustment_get_value(vscroll) + nsgtk_adjustment_get_page_increment(vscroll); if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; gtk_adjustment_set_value(vscroll, value); break; default: break; } return TRUE; } static gboolean nsgtk_window_size_allocate_event(GtkWidget *widget, GtkAllocation *allocation, gpointer data) { struct gui_window *g = data; g->bw->reformat_pending = true; browser_reformat_pending = true; if (g->paned != NULL) { /* Set status bar / scroll bar proportion according to * option_toolbar_status_width */ /* TODO: Probably want to detect when the user adjusts the * status bar width, remember that proportion for the * window, and use that here. */ gtk_paned_set_position(g->paned, (nsoption_int(toolbar_status_width) * allocation->width) / 10000); } return TRUE; } /* Core interface docuemnted in desktop/gui.h to create a gui_window */ struct gui_window *gui_create_browser_window(struct browser_window *bw, struct browser_window *clone, bool new_tab) { struct gui_window *g; /**< what we're creating to return */ g = calloc(1, sizeof(*g)); if (!g) { warn_user("NoMemory", 0); return 0; } LOG(("Creating gui window %p for browser window %p", g, bw)); g->bw = bw; g->paned = NULL; g->mouse.state = 0; g->current_pointer = GUI_POINTER_DEFAULT; if (clone != NULL) { bw->scale = clone->scale; } else { bw->scale = (float) nsoption_int(scale) / 100.0; } g->careth = 0; if (new_tab) { assert(clone != NULL); g->scaffold = clone->window->scaffold; } else { /* Now construct and attach a scaffold */ g->scaffold = nsgtk_new_scaffolding(g); } if (g->scaffold == NULL) { warn_user("NoMemory", 0); free(g); return NULL; } /* Construct our primary elements */ /* top-level document (not a frame) => create a new tab */ GError* error = NULL; GtkBuilder* xml = gtk_builder_new(); if (!gtk_builder_add_from_file(xml, glade_file_location->tabcontents, &error)) { g_warning ("Couldn't load builder file: %s", error->message); g_error_free(error); return 0; } g->layout = GTK_LAYOUT(gtk_builder_get_object(xml, "layout")); g->status_bar = GTK_LABEL(gtk_builder_get_object(xml, "status_bar")); g->paned = GTK_PANED(gtk_builder_get_object(xml, "hpaned1")); /* connect the scrollbars to the layout widget */ nsgtk_layout_set_hadjustment(g->layout, gtk_range_get_adjustment(GTK_RANGE( gtk_builder_get_object(xml, "hscrollbar")))); nsgtk_layout_set_vadjustment(g->layout, gtk_range_get_adjustment(GTK_RANGE( gtk_builder_get_object(xml, "vscrollbar")))); /* add the tab to the scaffold */ bool tempback = true; switch (temp_open_background) { case -1: tempback = !(nsoption_bool(focus_new)); break; case 0: tempback = false; break; case 1: tempback = true; break; } GtkWidget *tab_contents = GTK_WIDGET(gtk_builder_get_object(xml, "tabContents")); g_object_set_data(G_OBJECT(tab_contents), "gui_window", g); nsgtk_tab_add(g, tab_contents, tempback); g_object_unref(xml); /* Attach ourselves to the list (push_top) */ if (window_list) window_list->prev = g; g->next = window_list; g->prev = NULL; window_list = g; /* set the events we're interested in receiving from the browser's * drawing area. */ gtk_widget_add_events(GTK_WIDGET(g->layout), GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_SCROLL_MASK); nsgtk_widget_set_can_focus(GTK_WIDGET(g->layout), TRUE); /* set the default background colour of the drawing area to white. */ nsgtk_widget_override_background_color(GTK_WIDGET(g->layout), GTK_STATE_NORMAL, 0, 0xffff, 0xffff, 0xffff); nsgtk_connect_draw_event(GTK_WIDGET(g->layout), G_CALLBACK(nsgtk_window_draw_event), g); #define CONNECT(obj, sig, callback, ptr) \ g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) CONNECT(g->layout, "motion_notify_event", nsgtk_window_motion_notify_event, g); g->signalhandler[NSGTK_WINDOW_SIGNAL_CLICK] = CONNECT(g->layout, "button_press_event", nsgtk_window_button_press_event, g); CONNECT(g->layout, "button_release_event", nsgtk_window_button_release_event, g); CONNECT(g->layout, "key_press_event", nsgtk_window_keypress_event, g); CONNECT(g->layout, "size_allocate", nsgtk_window_size_allocate_event, g); CONNECT(g->layout, "scroll_event", nsgtk_window_scroll_event, g); return g; } void nsgtk_reflow_all_windows(void) { for (struct gui_window *g = window_list; g; g = g->next) { nsgtk_tab_options_changed( nsgtk_scaffolding_notebook(g->scaffold)); g->bw->reformat_pending = true; } browser_reformat_pending = true; } /** * Process pending reformats */ void nsgtk_window_process_reformats(void) { struct gui_window *g; GtkAllocation alloc; browser_reformat_pending = false; for (g = window_list; g; g = g->next) { if (!g->bw->reformat_pending) continue; g->bw->reformat_pending = false; /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); browser_window_reformat(g->bw, false, alloc.width, alloc.height); } } void nsgtk_window_destroy_browser(struct gui_window *g) { browser_window_destroy(g->bw); } void gui_window_destroy(struct gui_window *g) { if (g->prev) g->prev->next = g->next; else window_list = g->next; if (g->next) g->next->prev = g->prev; LOG(("Destroying gui_window %p", g)); assert(g != NULL); assert(g->bw != NULL); LOG((" Scaffolding: %p", g->scaffold)); LOG((" Window name: %s", g->bw->name)); /* tab => remove tab */ gtk_widget_destroy(gtk_widget_get_parent(GTK_WIDGET(g->layout))); } /** * set favicon */ void gui_window_set_icon(struct gui_window *gw, hlcache_handle *icon) { struct bitmap *icon_bitmap = NULL; /* free any existing icon */ if (gw->icon != NULL) { g_object_unref(gw->icon); gw->icon = NULL; } if (icon != NULL) { icon_bitmap = content_get_bitmap(icon); if (icon_bitmap != NULL) { LOG(("Using %p bitmap", icon_bitmap)); gw->icon = nsgdk_pixbuf_get_from_surface(icon_bitmap->surface, 16, 16); } } if (gw->icon == NULL) { LOG(("Using default favicon")); g_object_ref(favicon_pixbuf); gw->icon = favicon_pixbuf; } nsgtk_scaffolding_set_icon(gw); } static void nsgtk_redraw_caret(struct gui_window *g) { int sx, sy; if (g->careth == 0) return; gui_window_get_scroll(g, &sx, &sy); gtk_widget_queue_draw_area(GTK_WIDGET(g->layout), g->caretx - sx, g->carety - sy, 1, g->careth + 1); }
static void fb_redraw(fbtk_widget_t *widget, struct browser_widget_s *bwidget, struct browser_window *bw) { int x; int y; int caret_x, caret_y, caret_h; struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &fb_plotters }; nsfb_t *nsfb = fbtk_get_nsfb(widget); float scale = browser_window_get_scale(bw); LOG(("%d,%d to %d,%d", bwidget->redraw_box.x0, bwidget->redraw_box.y0, bwidget->redraw_box.x1, bwidget->redraw_box.y1)); x = fbtk_get_absx(widget); y = fbtk_get_absy(widget); /* adjust clipping co-ordinates according to window location */ bwidget->redraw_box.y0 += y; bwidget->redraw_box.y1 += y; bwidget->redraw_box.x0 += x; bwidget->redraw_box.x1 += x; nsfb_claim(nsfb, &bwidget->redraw_box); /* redraw bounding box is relative to window */ clip.x0 = bwidget->redraw_box.x0; clip.y0 = bwidget->redraw_box.y0; clip.x1 = bwidget->redraw_box.x1; clip.y1 = bwidget->redraw_box.y1; browser_window_redraw(bw, (x - bwidget->scrollx) / scale, (y - bwidget->scrolly) / scale, &clip, &ctx); if (fbtk_get_caret(widget, &caret_x, &caret_y, &caret_h)) { /* This widget has caret, so render it */ nsfb_bbox_t line; nsfb_plot_pen_t pen; line.x0 = x - bwidget->scrollx + caret_x; line.y0 = y - bwidget->scrolly + caret_y; line.x1 = x - bwidget->scrollx + caret_x; line.y1 = y - bwidget->scrolly + caret_y + caret_h; pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID; pen.stroke_width = 1; pen.stroke_colour = 0xFF0000FF; nsfb_plot_line(nsfb, &line, &pen); } nsfb_update(fbtk_get_nsfb(widget), &bwidget->redraw_box); bwidget->redraw_box.y0 = bwidget->redraw_box.x0 = INT_MAX; bwidget->redraw_box.y1 = bwidget->redraw_box.x1 = INT_MIN; bwidget->redraw_required = false; } static int fb_browser_window_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi) { struct gui_window *gw = cbi->context; struct browser_widget_s *bwidget; bwidget = fbtk_get_userpw(widget); if (bwidget == NULL) { LOG(("browser widget from widget %p was null", widget)); return -1; } if (bwidget->pan_required) { fb_pan(widget, bwidget, gw->bw); } if (bwidget->redraw_required) { fb_redraw(widget, bwidget, gw->bw); } else { bwidget->redraw_box.x0 = 0; bwidget->redraw_box.y0 = 0; bwidget->redraw_box.x1 = fbtk_get_width(widget); bwidget->redraw_box.y1 = fbtk_get_height(widget); fb_redraw(widget, bwidget, gw->bw); } return 0; } static int fb_browser_window_destroy(fbtk_widget_t *widget, fbtk_callback_info *cbi) { struct browser_widget_s *browser_widget; if (widget == NULL) { return 0; } /* Free private data */ browser_widget = fbtk_get_userpw(widget); free(browser_widget); return 0; } static const char *fename; static int febpp; static int fewidth; static int feheight; static const char *feurl; static bool process_cmdline(int argc, char** argv) { int opt; LOG(("argc %d, argv %p", argc, argv)); fename = "mtl"; febpp = 32; fewidth = nsoption_int(window_width); if (fewidth <= 0) { fewidth = 800; } feheight = nsoption_int(window_height); if (feheight <= 0) { feheight = 480; } if ((nsoption_charp(homepage_url) != NULL) && (nsoption_charp(homepage_url)[0] != '\0')) { feurl = nsoption_charp(homepage_url); } else { feurl = NETSURF_HOMEPAGE; } while((opt = getopt(argc, argv, "f:b:w:h:")) != -1) { switch (opt) { case 'f': fename = optarg; break; case 'b': febpp = atoi(optarg); break; case 'w': fewidth = atoi(optarg); break; case 'h': feheight = atoi(optarg); break; default: fprintf(stderr, "Usage: %s [-f frontend] [-b bpp] url\n", argv[0]); return false; } } if (optind < argc) { feurl = argv[optind]; } return true; }
static gboolean nsgtk_window_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data) { struct gui_window *gw = data; struct gui_window *z; struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &nsgtk_plotters }; double x1; double y1; double x2; double y2; assert(gw); assert(gw->bw); for (z = window_list; z && z != gw; z = z->next) continue; assert(z); assert(GTK_WIDGET(gw->layout) == widget); current_widget = (GtkWidget *)gw->layout; current_cr = cr; GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(gw->layout); GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(gw->layout); cairo_clip_extents(cr, &x1, &y1, &x2, &y2); clip.x0 = x1; clip.y0 = y1; clip.x1 = x2; clip.y1 = y2; browser_window_redraw(gw->bw, -gtk_adjustment_get_value(hscroll), -gtk_adjustment_get_value(vscroll), &clip, &ctx); if (gw->careth != 0) { nsgtk_plot_caret(gw->caretx, gw->carety, gw->careth); } current_widget = NULL; return FALSE; } #else static gboolean nsgtk_window_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { struct gui_window *gw = data; struct gui_window *z; struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &nsgtk_plotters }; assert(gw); assert(gw->bw); for (z = window_list; z && z != gw; z = z->next) continue; assert(z); assert(GTK_WIDGET(gw->layout) == widget); current_widget = (GtkWidget *)gw->layout; current_cr = gdk_cairo_create(nsgtk_layout_get_bin_window(gw->layout)); clip.x0 = event->area.x; clip.y0 = event->area.y; clip.x1 = event->area.x + event->area.width; clip.y1 = event->area.y + event->area.height; browser_window_redraw(gw->bw, 0, 0, &clip, &ctx); if (gw->careth != 0) { nsgtk_plot_caret(gw->caretx, gw->carety, gw->careth); } cairo_destroy(current_cr); current_widget = NULL; return FALSE; } #endif static gboolean nsgtk_window_motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) { struct gui_window *g = data; bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; if ((abs(event->x - g->last_x) < 5) && (abs(event->y - g->last_y) < 5)) { /* Mouse hasn't moved far enough from press coordinate for this * to be considered a drag. */ return FALSE; } else { /* This is a drag, ensure it's always treated as such, even if * we drag back over the press location */ g->last_x = INT_MIN; g->last_y = INT_MIN; } if (g->mouse.state & BROWSER_MOUSE_PRESS_1) { /* Start button 1 drag */ browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_1, g->mouse.pressed_x, g->mouse.pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_HOLDING_1); g->mouse.state |= BROWSER_MOUSE_DRAG_ON; } else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) { /* Start button 2 drag */ browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_2, g->mouse.pressed_x, g->mouse.pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_HOLDING_2); g->mouse.state |= BROWSER_MOUSE_DRAG_ON; } /* Handle modifiers being removed */ if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) g->mouse.state ^= BROWSER_MOUSE_MOD_1; if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) g->mouse.state ^= BROWSER_MOUSE_MOD_2; browser_window_mouse_track(g->bw, g->mouse.state, event->x / browser_window_get_scale(g->bw), event->y / browser_window_get_scale(g->bw)); return TRUE; } static gboolean nsgtk_window_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct gui_window *g = data; gtk_widget_grab_focus(GTK_WIDGET(g->layout)); gtk_widget_hide(GTK_WIDGET(nsgtk_scaffolding_history_window( g->scaffold)->window)); g->mouse.pressed_x = event->x / browser_window_get_scale(g->bw); g->mouse.pressed_y = event->y / browser_window_get_scale(g->bw); switch (event->button) { case 1: /* Left button, usually. Pass to core as BUTTON 1. */ g->mouse.state = BROWSER_MOUSE_PRESS_1; break; case 2: /* Middle button, usually. Pass to core as BUTTON 2 */ g->mouse.state = BROWSER_MOUSE_PRESS_2; break; case 3: /* Right button, usually. Action button, context menu. */ browser_window_remove_caret(g->bw, true); nsgtk_scaffolding_popup_menu(g->scaffold, g->mouse.pressed_x, g->mouse.pressed_y); return TRUE; default: return FALSE; } /* Modify for double & triple clicks */ if (event->type == GDK_3BUTTON_PRESS) g->mouse.state |= BROWSER_MOUSE_TRIPLE_CLICK; else if (event->type == GDK_2BUTTON_PRESS) g->mouse.state |= BROWSER_MOUSE_DOUBLE_CLICK; /* Handle the modifiers too */ if (event->state & GDK_SHIFT_MASK) g->mouse.state |= BROWSER_MOUSE_MOD_1; if (event->state & GDK_CONTROL_MASK) g->mouse.state |= BROWSER_MOUSE_MOD_2; /* Record where we pressed, for use when determining whether to start * a drag in motion notify events. */ g->last_x = event->x; g->last_y = event->y; browser_window_mouse_click(g->bw, g->mouse.state, g->mouse.pressed_x, g->mouse.pressed_y); return TRUE; } static gboolean nsgtk_window_button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct gui_window *g = data; bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; /* If the mouse state is PRESS then we are waiting for a release to emit * a click event, otherwise just reset the state to nothing */ if (g->mouse.state & BROWSER_MOUSE_PRESS_1) g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2); /* Handle modifiers being removed */ if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) g->mouse.state ^= BROWSER_MOUSE_MOD_1; if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) g->mouse.state ^= BROWSER_MOUSE_MOD_2; if (g->mouse.state & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2)) { browser_window_mouse_click(g->bw, g->mouse.state, event->x / browser_window_get_scale(g->bw), event->y / browser_window_get_scale(g->bw)); } else { browser_window_mouse_track(g->bw, 0, event->x / browser_window_get_scale(g->bw), event->y / browser_window_get_scale(g->bw)); } g->mouse.state = 0; return TRUE; } static gboolean nsgtk_window_scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) { struct gui_window *g = data; double value; double deltax = 0; double deltay = 0; GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(g->layout); GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(g->layout); GtkAllocation alloc; switch (event->direction) { case GDK_SCROLL_LEFT: deltax = -1.0; break; case GDK_SCROLL_UP: deltay = -1.0; break; case GDK_SCROLL_RIGHT: deltax = 1.0; break; case GDK_SCROLL_DOWN: deltay = 1.0; break; #if GTK_CHECK_VERSION(3,4,0) case GDK_SCROLL_SMOOTH: gdk_event_get_scroll_deltas((GdkEvent *)event, &deltax, &deltay); break; #endif default: LOG(("Unhandled mouse scroll direction")); return TRUE; } deltax *= nsgtk_adjustment_get_step_increment(hscroll); deltay *= nsgtk_adjustment_get_step_increment(vscroll); if (browser_window_scroll_at_point(g->bw, event->x / browser_window_get_scale(g->bw), event->y / browser_window_get_scale(g->bw), deltax, deltay) != true) { /* core did not handle event so change adjustments */ /* Horizontal */ if (deltax != 0) { value = gtk_adjustment_get_value(hscroll) + deltax; /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); if (value > nsgtk_adjustment_get_upper(hscroll) - alloc.width) { value = nsgtk_adjustment_get_upper(hscroll) - alloc.width; } if (value < nsgtk_adjustment_get_lower(hscroll)) { value = nsgtk_adjustment_get_lower(hscroll); } gtk_adjustment_set_value(hscroll, value); } /* Vertical */ if (deltay != 0) { value = gtk_adjustment_get_value(vscroll) + deltay; /* @todo consider gtk_widget_get_allocated_height */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); if (value > (nsgtk_adjustment_get_upper(vscroll) - alloc.height)) { value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; } if (value < nsgtk_adjustment_get_lower(vscroll)) { value = nsgtk_adjustment_get_lower(vscroll); } gtk_adjustment_set_value(vscroll, value); } } return TRUE; } static gboolean nsgtk_window_keypress_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct gui_window *g = data; uint32_t nskey = gtk_gui_gdkkey_to_nskey(event); if (browser_window_key_press(g->bw, nskey)) return TRUE; if ((event->state & 0x7) != 0) return TRUE; double value; GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(g->layout); GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(g->layout); GtkAllocation alloc; /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); switch (event->keyval) { case GDK_KEY(Home): case GDK_KEY(KP_Home): value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(End): case GDK_KEY(KP_End): value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Left): case GDK_KEY(KP_Left): value = gtk_adjustment_get_value(hscroll) - nsgtk_adjustment_get_step_increment(hscroll); if (value < nsgtk_adjustment_get_lower(hscroll)) value = nsgtk_adjustment_get_lower(hscroll); gtk_adjustment_set_value(hscroll, value); break; case GDK_KEY(Up): case GDK_KEY(KP_Up): value = gtk_adjustment_get_value(vscroll) - nsgtk_adjustment_get_step_increment(vscroll); if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Right): case GDK_KEY(KP_Right): value = gtk_adjustment_get_value(hscroll) + nsgtk_adjustment_get_step_increment(hscroll); if (value > nsgtk_adjustment_get_upper(hscroll) - alloc.width) value = nsgtk_adjustment_get_upper(hscroll) - alloc.width; gtk_adjustment_set_value(hscroll, value); break; case GDK_KEY(Down): case GDK_KEY(KP_Down): value = gtk_adjustment_get_value(vscroll) + nsgtk_adjustment_get_step_increment(vscroll); if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Page_Up): case GDK_KEY(KP_Page_Up): value = gtk_adjustment_get_value(vscroll) - nsgtk_adjustment_get_page_increment(vscroll); if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Page_Down): case GDK_KEY(KP_Page_Down): value = gtk_adjustment_get_value(vscroll) + nsgtk_adjustment_get_page_increment(vscroll); if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; gtk_adjustment_set_value(vscroll, value); break; default: break; } return TRUE; } static gboolean nsgtk_window_size_allocate_event(GtkWidget *widget, GtkAllocation *allocation, gpointer data) { struct gui_window *g = data; g->bw->reformat_pending = true; browser_reformat_pending = true; return TRUE; } /** when the pane position is changed update the user option * * The slightly awkward implementation with the first allocation flag * is necessary because the initial window creation does not cause an * allocate-event signal so the position value in the pane is incorrect * and we cannot know what it should be until after the allocation * (which did not generate a signal) is done as the user position is a * percentage of pane total width not an absolute value. */ static void nsgtk_paned_notify__position(GObject *gobject, GParamSpec *pspec, gpointer data) { struct gui_window *g = data; GtkAllocation pane_alloc; gtk_widget_get_allocation(GTK_WIDGET(g->paned), &pane_alloc); if (g->paned_sized == false) { g->paned_sized = true; gtk_paned_set_position(g->paned, (nsoption_int(toolbar_status_size) * pane_alloc.width) / 10000); return; } nsoption_set_int(toolbar_status_size, ((gtk_paned_get_position(g->paned) * 10000) / (pane_alloc.width - 1))); } /** Set status bar / scroll bar proportion according to user option * when pane is resized. */ static gboolean nsgtk_paned_size_allocate_event(GtkWidget *widget, GtkAllocation *allocation, gpointer data) { gtk_paned_set_position(GTK_PANED(widget), (nsoption_int(toolbar_status_size) * allocation->width) / 10000); return TRUE; } /* destroy the browsing context as there is nothing to display it now */ static void window_destroy(GtkWidget *widget, gpointer data) { struct gui_window *gw = data; browser_window_destroy(gw->bw); } /* Core interface documented in desktop/gui.h to create a gui_window */ static struct gui_window * gui_window_create(struct browser_window *bw, struct gui_window *existing, gui_window_create_flags flags) { struct gui_window *g; /**< what we're creating to return */ GError* error = NULL; bool tempback; GtkBuilder* xml; /* open builder file first to ease error handling on faliure */ xml = gtk_builder_new(); if (!gtk_builder_add_from_file(xml, glade_file_location->tabcontents, &error)) { g_warning ("Couldn't load builder file: %s", error->message); g_error_free(error); return NULL; } g = calloc(1, sizeof(*g)); if (!g) { warn_user("NoMemory", 0); g_object_unref(xml); return NULL; } LOG(("Creating gui window %p for browser window %p", g, bw)); g->bw = bw; g->mouse.state = 0; g->current_pointer = GUI_POINTER_DEFAULT; if (flags & GW_CREATE_CLONE) { assert(existing != NULL); bw->scale = existing->bw->scale; } else { bw->scale = nsoption_int(scale) / 100; } /* attach scaffold */ if (flags & GW_CREATE_TAB) { assert(existing != NULL); g->scaffold = existing->scaffold; } else { /* Now construct and attach a scaffold */ g->scaffold = nsgtk_new_scaffolding(g); } if (g->scaffold == NULL) { warn_user("NoMemory", 0); free(g); g_object_unref(xml); return NULL; } /* Construct our primary elements */ g->container = GTK_WIDGET(gtk_builder_get_object(xml, "tabContents")); g->layout = GTK_LAYOUT(gtk_builder_get_object(xml, "layout")); g->status_bar = GTK_LABEL(gtk_builder_get_object(xml, "status_bar")); g->paned = GTK_PANED(gtk_builder_get_object(xml, "hpaned1")); /* add new gui window to global list (push_top) */ if (window_list) { window_list->prev = g; } g->next = window_list; g->prev = NULL; window_list = g; /* set the events we're interested in receiving from the browser's * drawing area. */ gtk_widget_add_events(GTK_WIDGET(g->layout), GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_SCROLL_MASK); nsgtk_widget_set_can_focus(GTK_WIDGET(g->layout), TRUE); /* set the default background colour of the drawing area to white. */ nsgtk_widget_override_background_color(GTK_WIDGET(g->layout), GTK_STATE_NORMAL, 0, 0xffff, 0xffff, 0xffff); nsgtk_connect_draw_event(GTK_WIDGET(g->layout), G_CALLBACK(nsgtk_window_draw_event), g); /* layout signals */ CONNECT(g->layout, "motion-notify-event", nsgtk_window_motion_notify_event, g); g->signalhandler[NSGTK_WINDOW_SIGNAL_CLICK] = CONNECT(g->layout, "button-press-event", nsgtk_window_button_press_event, g); CONNECT(g->layout, "button-release-event", nsgtk_window_button_release_event, g); CONNECT(g->layout, "key-press-event", nsgtk_window_keypress_event, g); CONNECT(g->layout, "size-allocate", nsgtk_window_size_allocate_event, g); CONNECT(g->layout, "scroll-event", nsgtk_window_scroll_event, g); /* status pane signals */ CONNECT(g->paned, "size-allocate", nsgtk_paned_size_allocate_event, g); CONNECT(g->paned, "notify::position", nsgtk_paned_notify__position, g); /* gtk container destructor */ CONNECT(g->container, "destroy", window_destroy, g); /* add the tab container to the scaffold notebook */ switch (temp_open_background) { case -1: tempback = !(nsoption_bool(focus_new)); break; case 0: tempback = false; break; default: tempback = true; break; } nsgtk_tab_add(g, g->container, tempback); /* safe to drop the reference to the xml as the container is * referenced by the notebook now. */ g_object_unref(xml); return g; } void nsgtk_reflow_all_windows(void) { for (struct gui_window *g = window_list; g; g = g->next) { nsgtk_tab_options_changed( nsgtk_scaffolding_notebook(g->scaffold)); g->bw->reformat_pending = true; } browser_reformat_pending = true; } /** * Process pending reformats */ void nsgtk_window_process_reformats(void) { struct gui_window *g; GtkAllocation alloc; browser_reformat_pending = false; for (g = window_list; g; g = g->next) { if (!g->bw->reformat_pending) continue; g->bw->reformat_pending = false; /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); browser_window_reformat(g->bw, false, alloc.width, alloc.height); } } void nsgtk_window_destroy_browser(struct gui_window *gw) { /* remove tab */ gtk_widget_destroy(gw->container); }
void browser_redraw( struct gui_window * gw ) { LGRECT bwrect; struct s_browser * b = gw->browser; short todo[4]; struct rect clip; /* used for clipping of content redraw: */ struct rect redraw_area; if( b->attached == false || b->bw->current_content == NULL ) { return; } browser_get_rect(gw, BR_CONTENT, &bwrect); plotter->resize(plotter, bwrect.g_w, bwrect.g_h); plotter->move(plotter, bwrect.g_x, bwrect.g_y ); clip.x0 = 0; clip.y0 = 0; clip.x1 = bwrect.g_w; clip.y1 = bwrect.g_h; plotter->set_clip( plotter, &clip ); if( plotter->lock(plotter) == 0 ) return; if( b->scroll.required == true && b->bw->current_content != NULL) { browser_process_scroll( gw, bwrect ); b->scroll.required = false; } if ((b->redraw.areas_used > 0) && b->bw->current_content != NULL ) { if( (plotter->flags & PLOT_FLAG_OFFSCREEN) == 0 ) { int i; GRECT area; GRECT fbwork; short wf_top[4]; todo[0] = bwrect.g_x; todo[1] = bwrect.g_y; todo[2] = todo[0] + bwrect.g_w-1; todo[3] = todo[1] + bwrect.g_h-1; vs_clip(plotter->vdi_handle, 1, (short*)&todo[0]); wind_get( 0, WF_TOP, &wf_top[0], &wf_top[1], &wf_top[2], &wf_top[3] ); if( wf_top[0] == gw->root->handle->handle && wf_top[1] == _AESapid ){ /* The window is on top, so there is no need to walk the */ /* AES rectangle list. */ for( i=0; i<b->redraw.areas_used; i++ ){ fbwork.g_x = todo[0] - bwrect.g_x; fbwork.g_y = todo[1] - bwrect.g_y; if( fbwork.g_x < 0 ){ fbwork.g_w = todo[2] + todo[0]; fbwork.g_x = 0; } else { fbwork.g_w = todo[2]; } if( fbwork.g_y < 0 ){ fbwork.g_h = todo[3] + todo[1]; fbwork.g_y = 0; } else { fbwork.g_h = todo[3]; } area.g_x = b->redraw.areas[i].x0; area.g_y = b->redraw.areas[i].y0; area.g_w = b->redraw.areas[i].x1 - b->redraw.areas[i].x0; area.g_h = b->redraw.areas[i].y1 - b->redraw.areas[i].y0; if (rc_intersect((GRECT *)&fbwork,(GRECT *)&area)) { redraw_area.x0 = area.g_x; redraw_area.y0 = area.g_y; redraw_area.x1 = area.g_x + area.g_w; redraw_area.y1 = area.g_y + area.g_h; browser_redraw_content( gw, 0, 0, &redraw_area ); } else { /* the area should be kept scheduled for later redraw,*/ /* but because this is onscreen plotter, it doesn't */ /* make much sense anyway... */ } } } else { /* walk the AES rectangle list: */ if( wind_get(gw->root->handle->handle, WF_FIRSTXYWH, &todo[0], &todo[1], &todo[2], &todo[3] )!=0 ) { while (todo[2] && todo[3]) { /* convert screen to framebuffer coords: */ fbwork.g_x = todo[0] - bwrect.g_x; fbwork.g_y = todo[1] - bwrect.g_y; if( fbwork.g_x < 0 ){ fbwork.g_w = todo[2] + todo[0]; fbwork.g_x = 0; } else { fbwork.g_w = todo[2]; } if( fbwork.g_y < 0 ){ fbwork.g_h = todo[3] + todo[1]; fbwork.g_y = 0; } else { fbwork.g_h = todo[3]; } /* walk the redraw requests: */ for( i=0; i<b->redraw.areas_used; i++ ){ area.g_x = b->redraw.areas[i].x0; area.g_y = b->redraw.areas[i].y0; area.g_w = b->redraw.areas[i].x1 - b->redraw.areas[i].x0; area.g_h = b->redraw.areas[i].y1 - b->redraw.areas[i].y0; if (rc_intersect((GRECT *)&fbwork,(GRECT *)&area)) { redraw_area.x0 = area.g_x; redraw_area.y0 = area.g_y; redraw_area.x1 = area.g_x + area.g_w; redraw_area.y1 = area.g_y + area.g_h; browser_redraw_content( gw, 0, 0, &redraw_area ); } else { /* the area should be kept scheduled for later redraw,*/ /* but because this is onscreen plotter, it doesn't */ /* make much sense anyway... */ } } if (wind_get(gw->root->handle->handle, WF_NEXTXYWH, &todo[0], &todo[1], &todo[2], &todo[3])==0) { break; } } } } vs_clip(plotter->vdi_handle, 0, (short*)&todo); } else { /* its save to do a complete redraw without knowledge about GEM windows :) */ /* walk the redraw requests: */ int i; for( i=0; i<b->redraw.areas_used; i++ ){ struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &atari_plotters }; browser_window_redraw( b->bw, -b->scroll.current.x, -b->scroll.current.y, &b->redraw.areas[i], &ctx ); } GRECT area; area.g_x = bwrect.g_x; area.g_y = bwrect.g_y; area.g_w = bwrect.g_w; area.g_h = bwrect.g_h; //plotter->blit( plotter, &area ); } b->redraw.areas_used = 0; } if( b->caret.redraw == true && b->bw->current_content != NULL ) { LGRECT area; todo[0] = bwrect.g_x; todo[1] = bwrect.g_y; todo[2] = todo[0] + bwrect.g_w; todo[3] = todo[1] + bwrect.g_h; area.g_x = bwrect.g_x; area.g_y = bwrect.g_y; area.g_w = bwrect.g_w; area.g_h = bwrect.g_h; vs_clip(plotter->vdi_handle, 1, (short*)&todo[0]); browser_redraw_caret( gw, &area ); vs_clip(plotter->vdi_handle, 0, (short*)&todo[0]); b->caret.redraw = false; } plotter->unlock(plotter); /* TODO: if we use offscreen bitmap, trigger content redraw here */ } static void __CDECL browser_evnt_redraw( COMPONENT * c, long buff[8], void * data) { struct gui_window * gw = (struct gui_window *) data; CMP_BROWSER b = gw->browser; LGRECT work, lclip; browser_get_rect( gw, BR_CONTENT, &work ); lclip = work; if ( !rc_lintersect( (LGRECT*)&buff[4], &lclip ) ) return; if( b->bw->current_content == NULL ){ short pxy[4]; pxy[0] = lclip.g_x; pxy[1] = lclip.g_y; pxy[2] = lclip.g_x + lclip.g_w - 1; pxy[3] = lclip.g_y + lclip.g_h - 1; vsf_color( gw->root->handle->graf->handle, WHITE ); vsf_perimeter( gw->root->handle->graf->handle, 0); vsf_interior( gw->root->handle->graf->handle, FIS_SOLID ); vsf_style( gw->root->handle->graf->handle, 1); v_bar( gw->root->handle->graf->handle, (short*)&pxy ); return; } /* convert redraw coords to framebuffer coords: */ lclip.g_x -= work.g_x; lclip.g_y -= work.g_y; if( lclip.g_x < 0 ) { lclip.g_w = work.g_w + lclip.g_x; lclip.g_x = 0; } if( lclip.g_y < 0 ) { lclip.g_h = work.g_h + lclip.g_y; lclip.g_y = 0; } if( lclip.g_h > 0 && lclip.g_w > 0 ) { if( gw->browser->reformat_pending == true ){ LGRECT newsize; gw->browser->reformat_pending = false; browser_get_rect(gw, BR_CONTENT, &newsize); /* this call will also schedule an redraw for the complete */ /* area. */ /* Resize must be handled here, because otherwise */ /* a redraw is scheduled twice (1. by the frontend, 2. by AES) */ browser_window_reformat(b->bw, false, newsize.g_w, newsize.g_h ); } else { browser_schedule_redraw( gw, lclip.g_x, lclip.g_y, lclip.g_x + lclip.g_w, lclip.g_y + lclip.g_h ); } } return; }