gboolean gdk_cairo_get_clip_rectangle (cairo_t *cr, GdkRectangle *rect) { double x1, y1, x2, y2; gboolean clip_exists; cairo_clip_extents (cr, &x1, &y1, &x2, &y2); clip_exists = x1 < x2 && y1 < y2; if (rect) { x1 = floor (x1); y1 = floor (y1); x2 = ceil (x2); y2 = ceil (y2); rect->x = CLAMP (x1, G_MININT, G_MAXINT); rect->y = CLAMP (y1, G_MININT, G_MAXINT); rect->width = CLAMP (x2 - x1, G_MININT, G_MAXINT); rect->height = CLAMP (y2 - y1, G_MININT, G_MAXINT); } return clip_exists; }
static gboolean _gtk_cairo_surface_extents (cairo_surface_t *surface, GdkRectangle *extents) { double x1, x2, y1, y2; cairo_t *cr; g_return_val_if_fail (surface != NULL, FALSE); g_return_val_if_fail (extents != NULL, FALSE); cr = cairo_create (surface); cairo_clip_extents (cr, &x1, &y1, &x2, &y2); x1 = floor (x1); y1 = floor (y1); x2 = ceil (x2); y2 = ceil (y2); x2 -= x1; y2 -= y1; if (x1 < G_MININT || x1 > G_MAXINT || y1 < G_MININT || y1 > G_MAXINT || x2 > G_MAXINT || y2 > G_MAXINT) { extents->x = extents->y = extents->width = extents->height = 0; return FALSE; } extents->x = x1; extents->y = y1; extents->width = x2; extents->height = y2; return TRUE; }
static PyObject * pycairo_clip_extents (PycairoContext *o) { double x1, y1, x2, y2; cairo_clip_extents (o->ctx, &x1, &y1, &x2, &y2); RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx); return Py_BuildValue("(dddd)", x1, y1, x2, y2); }
gfxRect gfxContext::GetClipExtents() { double xmin, ymin, xmax, ymax; cairo_clip_extents(mCairo, &xmin, &ymin, &xmax, &ymax); return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin); }
static VALUE cr_clip_extents (VALUE self) { double x1, y1, x2, y2; cairo_clip_extents (_SELF, &x1, &y1, &x2, &y2); cr_check_status (_SELF); return rb_ary_new3 (4, rb_float_new (x1), rb_float_new (y1), rb_float_new (x2), rb_float_new (y2)); }
static int cr_clip_extents (lua_State *L) { cairo_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_CONTEXT); double x1, y1, x2, y2; cairo_clip_extents(*obj, &x1, &y1, &x2, &y2); lua_pushnumber(L, x1); lua_pushnumber(L, y1); lua_pushnumber(L, x2); lua_pushnumber(L, y2); return 4; }
static gboolean draw(GtkWidget*, cairo_t* cr, wxGLCanvas* win) { win->m_exposed = true; if (win->m_cairoPaintContext == NULL) { win->m_cairoPaintContext = cr; cairo_reference(cr); } double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); win->GetUpdateRegion().Union(int(x1), int(y1), int(x2 - x1), int(y2 - y1)); return false; }
static cairo_bool_t check_clip_extents (const char *message, cairo_t *cr, double x, double y, double width, double height) { double ext_x1, ext_y1, ext_x2, ext_y2; cairo_clip_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2); if (ext_x1 == x && ext_y1 == y && ext_x2 == x + width && ext_y2 == y + height) return 1; cairo_test_log ("Error: %s; clip extents %f,%f,%f,%f should be %f,%f,%f,%f\n", message, ext_x1, ext_y1, ext_x2 - ext_x1, ext_y2 - ext_y1, x, y, width, height); return 0; }
static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) { // No GdkWindow to render to, so return true to fall back if (!i.context->gdkDrawable()) return true; // Painting is disabled so just claim to have succeeded if (i.context->paintingDisabled()) return false; GtkWidgetState mozState; setMozState(theme, &mozState, o); int flags; // We might want to make setting flags the caller's job at some point rather than doing it here. switch (type) { case MOZ_GTK_BUTTON: flags = GTK_RELIEF_NORMAL; break; case MOZ_GTK_CHECKBUTTON: case MOZ_GTK_RADIOBUTTON: flags = theme->isChecked(o); break; default: flags = 0; break; } AffineTransform ctm = i.context->getCTM(); IntPoint pos = ctm.mapPoint(rect.location()); GdkRectangle gdkRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height()); GtkTextDirection direction = gtkTextDirection(o->style()->direction()); // Find the clip rectangle cairo_t *cr = i.context->platformContext(); double clipX1, clipX2, clipY1, clipY2; cairo_clip_extents(cr, &clipX1, &clipY1, &clipX2, &clipY2); GdkRectangle gdkClipRect; gdkClipRect.width = clipX2 - clipX1; gdkClipRect.height = clipY2 - clipY1; IntPoint clipPos = ctm.mapPoint(IntPoint(clipX1, clipY1)); gdkClipRect.x = clipPos.x(); gdkClipRect.y = clipPos.y(); gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect); return moz_gtk_widget_paint(type, i.context->gdkDrawable(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS; }
static int ui_clip_extents(lua_State *L) { double x, y, w, h; struct context *c = lua_touserdata(L, 1); cairo_clip_extents(c->cr, &x, &y, &w, &h); lua_pushnumber(L, x); lua_pushnumber(L, y); lua_pushnumber(L, w); lua_pushnumber(L, h); return 4; }
void GraphicsContext::clipOut(const IntRect& r) { if (paintingDisabled()) return; cairo_t* cr = platformContext()->cr(); double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height()); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); }
void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) return; cairo_t* cr = platformContext()->cr(); double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); appendWebCorePathToCairoContext(cr, path); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); }
void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) return; cairo_t* cr = m_data->cr; double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); addPath(path); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); }
static int cairo_clip_extents_l( lua_State* L ) { double x1 = 0.0; double y1 = 0.0; double x2 = 0.0; double y2 = 0.0; lua_cairo_t* lc = lua_cairo_check( L, 1 ); cairo_clip_extents( lc->cairo, &x1, &y1, &x2, &y2 ); lua_pushnumber( L, x1 ); lua_pushnumber( L, y1 ); lua_pushnumber( L, x2 ); lua_pushnumber( L, y2 ); return( 4 ); }
void GraphicsContext::clipOut(const IntRect& r) { if (paintingDisabled()) return; #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0) cairo_t* cr = m_data->cr; double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); cairo_rectangle(cr, x1, x2, x2 - x1, y2 - y1); cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height()); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); #else notImplemented(); #endif }
static void swfdec_shape_render (SwfdecGraphic *graphic, cairo_t *cr, const SwfdecColorTransform *trans) { SwfdecShape *shape = SWFDEC_SHAPE (graphic); SwfdecRect inval; GSList *walk; cairo_clip_extents (cr, &inval.x0, &inval.y0, &inval.x1, &inval.y1); for (walk = shape->draws; walk; walk = walk->next) { SwfdecDraw *draw = walk->data; if (!swfdec_rect_intersect (NULL, &draw->extents, &inval)) continue; swfdec_draw_paint (draw, cr, trans); } }
static void swfdec_morph_movie_render (SwfdecMovie *movie, cairo_t *cr, const SwfdecColorTransform *trans) { SwfdecMorphMovie *morph = SWFDEC_MORPH_MOVIE (movie); SwfdecRect inval; GSList *walk; if (morph->draws == NULL) swfdec_morph_movie_create_morphs (morph); cairo_clip_extents (cr, &inval.x0, &inval.y0, &inval.x1, &inval.y1); for (walk = morph->draws; walk; walk = walk->next) { SwfdecDraw *draw = walk->data; if (!swfdec_rect_intersect (NULL, &draw->extents, &inval)) continue; swfdec_draw_paint (draw, cr, trans); } }
void GraphicsContext::clipOut(const IntRect& rect) { if (paintingDisabled()) return; #if USE(WXGC) wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); #if wxUSE_CAIRO double x1, y1, x2, y2; cairo_t* cr = (cairo_t*)gc->GetNativeContext(); cairo_clip_extents(cr, &x1, &y1, &x2, &y2); cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); #elif __WXMAC__ CGContextRef context = (CGContextRef)gc->GetNativeContext(); CGRect rects[2] = { CGContextGetClipBoundingBox(context), CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()) }; CGContextBeginPath(context); CGContextAddRects(context, rects, 2); CGContextEOClip(context); return; #elif __WXMSW__ Gdiplus::Graphics* g = (Gdiplus::Graphics*)gc->GetNativeContext(); Gdiplus::Region excludeRegion(Gdiplus::Rect(rect.x(), rect.y(), rect.width(), rect.height())); g->ExcludeClip(&excludeRegion); return; #endif #endif // USE(WXGC) notImplemented(); }
void PlatformContextCairo::clipForPatternFilling(const GraphicsContextState& state) { ASSERT(state.fillPattern); // Hold current cairo path in a variable for restoring it after configuring the pattern clip rectangle. auto currentPath = cairo_copy_path(m_cr.get()); cairo_new_path(m_cr.get()); // Initialize clipping extent from current cairo clip extents, then shrink if needed according to pattern. // Inspired by GraphicsContextQt::drawRepeatPattern. double x1, y1, x2, y2; cairo_clip_extents(m_cr.get(), &x1, &y1, &x2, &y2); FloatRect clipRect(x1, y1, x2 - x1, y2 - y1); Image* patternImage = state.fillPattern->tileImage(); ASSERT(patternImage); const AffineTransform& patternTransform = state.fillPattern->getPatternSpaceTransform(); FloatRect patternRect = patternTransform.mapRect(FloatRect(0, 0, patternImage->width(), patternImage->height())); bool repeatX = state.fillPattern->repeatX(); bool repeatY = state.fillPattern->repeatY(); if (!repeatX) { clipRect.setX(patternRect.x()); clipRect.setWidth(patternRect.width()); } if (!repeatY) { clipRect.setY(patternRect.y()); clipRect.setHeight(patternRect.height()); } if (!repeatX || !repeatY) { cairo_rectangle(m_cr.get(), clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height()); cairo_clip(m_cr.get()); } // Restoring cairo path. cairo_append_path(m_cr.get(), currentPath); cairo_path_destroy(currentPath); }
void cairodraw_dblock(cairo_t * cr, pcdblock b, int levels) { double sx, sy, ex, ey; uint rsize, csize; double scalex, scaley, scale; /* Save Cairo state */ cairo_save(cr); /* Obtain size of block */ rsize = b->rc->size; csize = b->cc->size; /* Obtain size of current Cairo bounding box */ cairo_clip_extents(cr, &sx, &sy, &ex, &ey); /* Compute scaling factor */ scalex = (ex - sx) / rsize; scaley = (ey - sy) / csize; scale = (scalex < scaley ? scalex : scaley); /* Center block in bounding box */ cairo_translate(cr, 0.5 * (ex - sx - scale * rsize), 0.5 * (ey - sy - scale * csize)); /* Scale coordinates */ cairo_scale(cr, scale, scale); cairo_set_line_width(cr, cairo_get_line_width(cr) / scale); /* Start drawing */ cairodraw_subblock(cr, b, levels); /* Restore Cairo state */ cairo_restore(cr); }
void lime_cairo_clip_extents (value handle, double x1, double y1, double x2, double y2) { cairo_clip_extents ((cairo_t*)val_data (handle), &x1, &y1, &x2, &y2); }
void lime_cairo_clip_extents (double handle, double x1, double y1, double x2, double y2) { cairo_clip_extents ((cairo_t*)(intptr_t)handle, &x1, &y1, &x2, &y2); }
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); }
IntRect GraphicsContext::clipBounds() const { double x1, x2, y1, y2; cairo_clip_extents(platformContext()->cr(), &x1, &y1, &x2, &y2); return enclosingIntRect(FloatRect(x1, y1, x2 - x1, y2 - y1)); }
void Context::clipExtents( double *x1, double *y1, double *x2, double *y2 ) { cairo_clip_extents( mCairo, x1, y1, x2, y2 ); }
static void gtk_css_style_render_frame_gap (GtkCssStyle *style, cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height, GtkPositionType gap_side, gdouble xy0_gap, gdouble xy1_gap, GtkJunctionSides junction) { gint border_width; GtkCssValue *corner[4]; gdouble x0, y0, x1, y1, xc = 0.0, yc = 0.0, wc = 0.0, hc = 0.0; GtkBorder border; border.top = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100); border.right = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100); border.bottom = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100); border.left = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100); corner[GTK_CSS_TOP_LEFT] = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS); corner[GTK_CSS_TOP_RIGHT] = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS); corner[GTK_CSS_BOTTOM_LEFT] = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS); corner[GTK_CSS_BOTTOM_RIGHT] = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS); border_width = MIN (MIN (border.top, border.bottom), MIN (border.left, border.right)); cairo_save (cr); switch (gap_side) { case GTK_POS_TOP: xc = x + xy0_gap + border_width; yc = y; wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); hc = border_width; if (xy0_gap < _gtk_css_corner_value_get_x (corner[GTK_CSS_TOP_LEFT], width)) junction |= GTK_JUNCTION_CORNER_TOPLEFT; if (xy1_gap > width - _gtk_css_corner_value_get_x (corner[GTK_CSS_TOP_RIGHT], width)) junction |= GTK_JUNCTION_CORNER_TOPRIGHT; break; case GTK_POS_BOTTOM: xc = x + xy0_gap + border_width; yc = y + height - border_width; wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); hc = border_width; if (xy0_gap < _gtk_css_corner_value_get_x (corner[GTK_CSS_BOTTOM_LEFT], width)) junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT; if (xy1_gap > width - _gtk_css_corner_value_get_x (corner[GTK_CSS_BOTTOM_RIGHT], width)) junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT; break; case GTK_POS_LEFT: xc = x; yc = y + xy0_gap + border_width; wc = border_width; hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); if (xy0_gap < _gtk_css_corner_value_get_y (corner[GTK_CSS_TOP_LEFT], height)) junction |= GTK_JUNCTION_CORNER_TOPLEFT; if (xy1_gap > height - _gtk_css_corner_value_get_y (corner[GTK_CSS_BOTTOM_LEFT], height)) junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT; break; case GTK_POS_RIGHT: xc = x + width - border_width; yc = y + xy0_gap + border_width; wc = border_width; hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); if (xy0_gap < _gtk_css_corner_value_get_y (corner[GTK_CSS_TOP_RIGHT], height)) junction |= GTK_JUNCTION_CORNER_TOPRIGHT; if (xy1_gap > height - _gtk_css_corner_value_get_y (corner[GTK_CSS_BOTTOM_RIGHT], height)) junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT; break; } cairo_clip_extents (cr, &x0, &y0, &x1, &y1); cairo_rectangle (cr, x0, y0, x1 - x0, yc - y0); cairo_rectangle (cr, x0, yc, xc - x0, hc); cairo_rectangle (cr, xc + wc, yc, x1 - (xc + wc), hc); cairo_rectangle (cr, x0, yc + hc, x1 - x0, y1 - (yc + hc)); cairo_clip (cr); gtk_css_style_render_border (style, cr, x, y, width, height, 0, junction); cairo_restore (cr); }
PangoLayout* gdip_pango_setup_layout (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int length, GDIPCONST GpFont *font, GDIPCONST RectF *rc, RectF *box, GDIPCONST GpStringFormat *format, int **charsRemoved) { GpStringFormat *fmt; PangoLayout *layout; PangoContext *context; PangoRectangle logical; /* logical size of text (used for alignment) */ PangoRectangle ink; /* ink size of text (to pixel boundaries) */ PangoAttrList *list = NULL; GString *ftext; PangoTabArray *tabs; PangoLayoutIter *iter; int i; int FrameWidth; /* rc->Width (or rc->Height if vertical) */ int FrameHeight; /* rc->Height (or rc->Width if vertical) */ int FrameX; /* rc->X (or rc->Y if vertical) */ int FrameY; /* rc->Y (or rc->X if vertical) */ int y0; /* y0,y1,clipNN used for checking line positions vs. clip rectangle */ int y1; double clipx1; double clipx2; double clipy1; double clipy2; int trimSpace; /* whether or not to trim the space */ gchar *text = ucs2_to_utf8 (stringUnicode, length); if (!text) return NULL; length = strlen(text); if (charsRemoved) { (*charsRemoved) = GdipAlloc (sizeof (int) * length); if (!*charsRemoved) { GdipFree (text); return NULL; } memset (*charsRemoved, 0, sizeof (int) * length); } /* TODO - Digit substitution */ // g_warning ("layout >%s< (%d) [x %g, y %g, w %g, h %g] [font %s, %g points]", text, length, rc->X, rc->Y, rc->Width, FrameHeight, font->face, font->emSize); /* a NULL format is valid, it means get the generic default values (and free them later) */ if (!format) { GpStatus status = GdipStringFormatGetGenericDefault ((GpStringFormat **)&fmt); if (status != Ok) { GdipFree (text); return NULL; } } else { fmt = (GpStringFormat *)format; } layout = pango_cairo_create_layout (graphics->ct); /* context is owned by Pango (i.e. not referenced counted) do not free */ context = pango_layout_get_context (layout); pango_layout_set_font_description (layout, gdip_get_pango_font_description ((GpFont*) font)); if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { FrameWidth = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Height)); FrameHeight = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Width)); FrameX = SAFE_FLOAT_TO_UINT32 (rc->Y); FrameY = SAFE_FLOAT_TO_UINT32 (rc->X); } else { FrameWidth = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Width)); FrameHeight = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Height)); FrameX = SAFE_FLOAT_TO_UINT32 (rc->X); FrameY = SAFE_FLOAT_TO_UINT32 (rc->Y); } //g_warning("FW: %d\tFH: %d", FrameWidth, FrameHeight); if ((FrameWidth <= 0) || (fmt->formatFlags & StringFormatFlagsNoWrap)) { pango_layout_set_width (layout, -1); //g_warning ("Setting width: %d", -1); } else { pango_layout_set_width (layout, FrameWidth * PANGO_SCALE); //g_warning ("Setting width: %d", FrameWidth * PANGO_SCALE); } if ((rc->Width != 0) && (rc->Height != 0) && ((fmt->formatFlags & StringFormatFlagsNoClip) == 0)) { // g_warning ("\tclip [%g %g %g %g]", rc->X, rc->Y, rc->Width, rc->Height); /* We do not call cairo_reset_clip because we want to take previous clipping into account */ /* Use rc instead of frame variables because this is pre-transform */ gdip_cairo_rectangle (graphics, rc->X, rc->Y, rc->Width, rc->Height, TRUE); cairo_clip (graphics->ct); } /* with GDI+ the API not the renderer makes the direction decision */ pango_layout_set_auto_dir (layout, FALSE); if (!(fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) != !(fmt->formatFlags & StringFormatFlagsDirectionVertical)) { pango_context_set_base_dir (context, PANGO_DIRECTION_WEAK_RTL); pango_layout_context_changed (layout); /* horizontal alignment */ switch (fmt->alignment) { case StringAlignmentNear: pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); break; case StringAlignmentCenter: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); break; case StringAlignmentFar: pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); break; } } else { /* pango default base dir is WEAK_LTR, which is what we want */ /* horizontal alignment */ switch (fmt->alignment) { case StringAlignmentNear: pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); break; case StringAlignmentCenter: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); break; case StringAlignmentFar: pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); break; } } #ifdef PANGO_VERSION_CHECK #if PANGO_VERSION_CHECK(1,16,0) if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { if (fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) { cairo_rotate (graphics->ct, M_PI/2.0); cairo_translate (graphics->ct, 0, -FrameHeight); pango_cairo_update_context (graphics->ct, context); } else { cairo_rotate (graphics->ct, 3.0*M_PI/2.0); cairo_translate (graphics->ct, -FrameWidth, 0); pango_cairo_update_context (graphics->ct, context); } /* only since Pango 1.16 */ pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO); pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_LINE); pango_layout_context_changed (layout); } #endif #endif /* TODO - StringFormatFlagsDisplayFormatControl scan and replace them ??? */ /* Trimming options seem to apply only to the end of the string - gdi+ will still wrap * with preference to word first, then character. Unfortunately, pango doesn't have * any way to differentiate wrapping behavior from trimming behavior that I could find */ pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); switch (fmt->trimming) { case StringTrimmingNone: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); break; case StringTrimmingCharacter: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); break; case StringTrimmingWord: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); break; case StringTrimmingEllipsisCharacter: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); if (!(fmt->formatFlags & StringFormatFlagsNoWrap)) pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE); break; case StringTrimmingEllipsisWord: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); if (!(fmt->formatFlags & StringFormatFlagsNoWrap)) pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE); break; case StringTrimmingEllipsisPath: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_MIDDLE); if (!(fmt->formatFlags & StringFormatFlagsNoWrap)) pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE); break; } /* some stuff can only be done by manipulating the attributes (but we can avoid this most of the time) */ if ((fmt->formatFlags & StringFormatFlagsNoFontFallback) || (font->style & (FontStyleUnderline | FontStyleStrikeout))) { list = gdip_get_layout_attributes (layout); /* StringFormatFlagsNoFontFallback */ if (fmt->formatFlags & StringFormatFlagsNoFontFallback) { PangoAttribute *attr = pango_attr_fallback_new (FALSE); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert (list, attr); } if (font->style & FontStyleUnderline) { PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert (list, attr); } if (font->style & FontStyleStrikeout) { PangoAttribute *attr = pango_attr_strikethrough_new (TRUE); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert (list, attr); } } if (fmt->numtabStops > 0) { float tabPosition; tabs = pango_tab_array_new (fmt->numtabStops, FALSE); tabPosition = fmt->firstTabOffset; for (i = 0; i < fmt->numtabStops; i++) { tabPosition += fmt->tabStops[i]; pango_tab_array_set_tab (tabs, i, PANGO_TAB_LEFT, (gint)min (tabPosition, PANGO_MAX) * PANGO_SCALE); } pango_layout_set_tabs (layout, tabs); pango_tab_array_free (tabs); } //g_warning ("length before ws removal: %d", length); trimSpace = (fmt->formatFlags & StringFormatFlagsMeasureTrailingSpaces) == 0; switch (fmt->hotkeyPrefix) { case HotkeyPrefixHide: /* we need to remove any accelerator from the string */ ftext = gdip_process_string (text, length, 1, trimSpace, NULL, charsRemoved); break; case HotkeyPrefixShow: /* optimization: is seems that we never see the hotkey when using an underline font */ if (font->style & FontStyleUnderline) { /* so don't bother drawing it (and simply add the '&' character) */ ftext = gdip_process_string (text, length, 1, trimSpace, NULL, charsRemoved); } else { /* find accelerator and add attribute to the next character (unless it's the prefix too) */ if (!list) list = gdip_get_layout_attributes (layout); ftext = gdip_process_string (text, length, 1, trimSpace, list, charsRemoved); } break; default: ftext = gdip_process_string (text, length, 0, trimSpace, NULL, charsRemoved); break; } length = ftext->len; //g_warning ("length after ws removal: %d", length); if (list) { pango_layout_set_attributes (layout, list); pango_attr_list_unref (list); } // g_warning("\tftext>%s< (%d)", ftext->str, -1); pango_layout_set_text (layout, ftext->str, ftext->len); GdipFree (text); g_string_free(ftext, TRUE); /* Trim the text after the last line for ease of counting lines/characters */ /* Also prevents drawing whole lines outside the boundaries if NoClip was specified */ /* In case of pre-existing clipping, use smaller of clip rectangle or our specified height */ if (FrameHeight > 0) { cairo_clip_extents (graphics->ct, &clipx1, &clipy1, &clipx2, &clipy2); if (clipy2 > 0 && !(fmt->formatFlags & StringFormatFlagsNoClip)) clipy2 = min (clipy2, FrameHeight + FrameY); else clipy2 = FrameHeight + FrameY; iter = pango_layout_get_iter (layout); do { if (iter == NULL) break; pango_layout_iter_get_line_yrange (iter, &y0, &y1); //g_warning("yrange: %d %d clipy2: %f", y0 / PANGO_SCALE, y1 / PANGO_SCALE, clipy2); /* StringFormatFlagsLineLimit */ if (((fmt->formatFlags & StringFormatFlagsLineLimit) && y1 / PANGO_SCALE > clipy2) || (y0 / PANGO_SCALE > clipy2)) { PangoLayoutLine *line = pango_layout_iter_get_line_readonly (iter); pango_layout_set_text (layout, pango_layout_get_text (layout), line->start_index); break; } } while (pango_layout_iter_next_line (iter)); pango_layout_iter_free (iter); } pango_layout_get_pixel_extents (layout, &ink, &logical); // g_warning ("\tlogical\t[x %d, y %d, w %d, h %d][x %d, y %d, w %d, h %d]", logical.x, logical.y, logical.width, logical.height, ink.x, ink.y, ink.width, ink.height); if ((fmt->formatFlags & StringFormatFlagsNoFitBlackBox) == 0) { /* By default don't allow overhang - ink space may be larger than logical space */ if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { box->X = min (ink.y, logical.y); box->Y = min (ink.x, logical.x); box->Height = max (ink.width, logical.width); box->Width = max (ink.height, logical.height); } else { box->X = min (ink.x, logical.x); box->Y = min (ink.y, logical.y); box->Height = max (ink.height, logical.height); box->Width = max (ink.width, logical.width); } } else { /* Allow overhang */ if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { box->X = logical.y; box->Y = logical.x; box->Height = logical.width; box->Width = logical.height; } else { box->X = logical.x; box->Y = logical.y; box->Height = logical.height; box->Width = logical.width; } } // g_warning ("\tbox\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, box->Height); /* vertical alignment*/ if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { switch (fmt->lineAlignment) { case StringAlignmentNear: break; case StringAlignmentCenter: box->X += (rc->Width - box->Width) / 2; break; case StringAlignmentFar: box->X += (rc->Width - box->Width); break; } } else { switch (fmt->lineAlignment) { case StringAlignmentNear: break; case StringAlignmentCenter: box->Y += (rc->Height - box->Height) / 2; break; case StringAlignmentFar: box->Y += (rc->Height - box->Height); break; } } // g_warning ("va-box\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, box->Height); pango_cairo_update_layout (graphics->ct, layout); return layout; }
static gboolean nsgtk_tree_window_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data) { struct tree *tree = (struct tree *)data; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &nsgtk_plotters }; double x1; double y1; double x2; double y2; current_widget = widget; current_cr = cr; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); tree_draw(tree, 0, 0, x1, y1, x2 - x1, y2 - y1, &ctx); current_widget = NULL; return FALSE; } #else /* signal handler functions for a tree window */ static gboolean nsgtk_tree_window_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer g) { struct tree *tree = (struct tree *) g; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &nsgtk_plotters }; int x, y, width, height; x = event->area.x; y = event->area.y; width = event->area.width; height = event->area.height; current_widget = widget; current_cr = gdk_cairo_create(nsgtk_widget_get_window(widget)); tree_draw(tree, 0, 0, x, y, width, height, &ctx); current_widget = NULL; cairo_destroy(current_cr); return FALSE; } #endif void nsgtk_tree_window_hide(GtkWidget *widget, gpointer g) { } gboolean nsgtk_tree_window_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer g) { struct nsgtk_treeview *tw = g; struct tree *tree = tw->tree; gtk_widget_grab_focus(GTK_WIDGET(tw->drawing_area)); tw->mouse_pressed = true; tw->mouse_pressed_x = event->x; tw->mouse_pressed_y = event->y; if (event->type == GDK_2BUTTON_PRESS) tw->mouse_state = BROWSER_MOUSE_DOUBLE_CLICK; switch (event->button) { case 1: tw->mouse_state |= BROWSER_MOUSE_PRESS_1; break; case 2: tw->mouse_state |= BROWSER_MOUSE_PRESS_2; break; } /* Handle the modifiers too */ if (event->state & GDK_SHIFT_MASK) tw->mouse_state |= BROWSER_MOUSE_MOD_1; if (event->state & GDK_CONTROL_MASK) tw->mouse_state |= BROWSER_MOUSE_MOD_2; if (event->state & GDK_MOD1_MASK) tw->mouse_state |= BROWSER_MOUSE_MOD_3; /* Record where we pressed, for use when determining whether to start * a drag in motion notify events. */ tw->last_x = event->x; tw->last_y = event->y; tree_mouse_action(tree, tw->mouse_state, event->x, event->y); return TRUE; } gboolean nsgtk_tree_window_button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer g) { bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; bool alt = event->state & GDK_MOD1_MASK; struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g; struct tree *tree = tw->tree; /* We consider only button 1 clicks as double clicks. * 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 (tw->mouse_state & BROWSER_MOUSE_DOUBLE_CLICK) { if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) tw->mouse_state ^= BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1; else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2) tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2 | BROWSER_MOUSE_DOUBLE_CLICK); } else if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) { tw->mouse_state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); } else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2) { tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2); } else if (tw->mouse_state & BROWSER_MOUSE_HOLDING_1) { tw->mouse_state ^= (BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_DRAG_ON); } else if (tw->mouse_state & BROWSER_MOUSE_HOLDING_2) { tw->mouse_state ^= (BROWSER_MOUSE_HOLDING_2 | BROWSER_MOUSE_DRAG_ON); } /* Handle modifiers being removed */ if (tw->mouse_state & BROWSER_MOUSE_MOD_1 && !shift) tw->mouse_state ^= BROWSER_MOUSE_MOD_1; if (tw->mouse_state & BROWSER_MOUSE_MOD_2 && !ctrl) tw->mouse_state ^= BROWSER_MOUSE_MOD_2; if (tw->mouse_state & BROWSER_MOUSE_MOD_3 && !alt) tw->mouse_state ^= BROWSER_MOUSE_MOD_3; if (tw->mouse_state & ~(BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_2 | BROWSER_MOUSE_MOD_3)) { tree_mouse_action(tree, tw->mouse_state, event->x, event->y); } else { tree_drag_end(tree, tw->mouse_state, tw->mouse_pressed_x, tw->mouse_pressed_y, event->x, event->y); } tw->mouse_state = 0; tw->mouse_pressed = false; return TRUE; } gboolean nsgtk_tree_window_motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer g) { bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; bool alt = event->state & GDK_MOD1_MASK; struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g; struct tree *tree = tw->tree; if (tw->mouse_pressed == false) return TRUE; if ((abs(event->x - tw->last_x) < 5) && (abs(event->y - tw->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 */ tw->last_x = INT_MIN; tw->last_y = INT_MIN; } if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) { /* Start button 1 drag */ tree_mouse_action(tree, BROWSER_MOUSE_DRAG_1, tw->mouse_pressed_x, tw->mouse_pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ tw->mouse_state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_HOLDING_1); tw->mouse_state |= BROWSER_MOUSE_DRAG_ON; return TRUE; } else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2){ /* Start button 2s drag */ tree_mouse_action(tree, BROWSER_MOUSE_DRAG_2, tw->mouse_pressed_x, tw->mouse_pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_HOLDING_2); tw->mouse_state |= BROWSER_MOUSE_DRAG_ON; return TRUE; } /* Handle modifiers being removed */ if (tw->mouse_state & BROWSER_MOUSE_MOD_1 && !shift) tw->mouse_state ^= BROWSER_MOUSE_MOD_1; if (tw->mouse_state & BROWSER_MOUSE_MOD_2 && !ctrl) tw->mouse_state ^= BROWSER_MOUSE_MOD_2; if (tw->mouse_state & BROWSER_MOUSE_MOD_3 && !alt) tw->mouse_state ^= BROWSER_MOUSE_MOD_3; if (tw->mouse_state & (BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_HOLDING_2)) tree_mouse_action(tree, tw->mouse_state, event->x, event->y); 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; 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 gtk_css_style_render_frame_gap (GtkCssStyle *style, cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height, GtkPositionType gap_side, gdouble xy0_gap, gdouble xy1_gap) { gint border_width; gdouble x0, y0, x1, y1, xc = 0.0, yc = 0.0, wc = 0.0, hc = 0.0; GtkBorder border; border.top = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100); border.right = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100); border.bottom = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100); border.left = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100); border_width = MIN (MIN (border.top, border.bottom), MIN (border.left, border.right)); cairo_save (cr); switch (gap_side) { case GTK_POS_TOP: xc = x + xy0_gap + border_width; yc = y; wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); hc = border_width; break; case GTK_POS_BOTTOM: xc = x + xy0_gap + border_width; yc = y + height - border_width; wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); hc = border_width; break; case GTK_POS_LEFT: xc = x; yc = y + xy0_gap + border_width; wc = border_width; hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); break; case GTK_POS_RIGHT: xc = x + width - border_width; yc = y + xy0_gap + border_width; wc = border_width; hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); break; } cairo_clip_extents (cr, &x0, &y0, &x1, &y1); cairo_rectangle (cr, x0, y0, x1 - x0, yc - y0); cairo_rectangle (cr, x0, yc, xc - x0, hc); cairo_rectangle (cr, xc + wc, yc, x1 - (xc + wc), hc); cairo_rectangle (cr, x0, yc + hc, x1 - x0, y1 - (yc + hc)); cairo_clip (cr); gtk_css_style_render_border (style, cr, x, y, width, height); cairo_restore (cr); }