void meta_ui_theme_get_frame_borders (MetaUI *ui, MetaFrameType type, MetaFrameFlags flags, MetaFrameBorders *borders) { int text_height; GtkStyleContext *style = NULL; PangoContext *context; const PangoFontDescription *font_desc; PangoFontDescription *free_font_desc = NULL; if (meta_ui_have_a_theme ()) { context = gtk_widget_get_pango_context (GTK_WIDGET (ui->frames)); font_desc = meta_prefs_get_titlebar_font (); if (!font_desc) { GdkDisplay *display = gdk_x11_lookup_xdisplay (ui->xdisplay); GdkScreen *screen = gdk_display_get_screen (display, XScreenNumberOfScreen (ui->xscreen)); GtkWidgetPath *widget_path; style = gtk_style_context_new (); gtk_style_context_set_screen (style, screen); widget_path = gtk_widget_path_new (); gtk_widget_path_append_type (widget_path, GTK_TYPE_WINDOW); gtk_style_context_set_path (style, widget_path); gtk_widget_path_free (widget_path); gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, "font", &free_font_desc, NULL); font_desc = (const PangoFontDescription *) free_font_desc; } text_height = meta_pango_font_desc_get_text_height (font_desc, context); meta_theme_get_frame_borders (meta_theme_get_current (), type, text_height, flags, borders); if (free_font_desc) pango_font_description_free (free_font_desc); } else { meta_frame_borders_clear (borders); } if (style != NULL) g_object_unref (style); }
gfloat meta_get_title_scale (decor_frame_t *frame) { MetaTheme *theme = meta_theme_get_current (); MetaFrameType type; MetaFrameFlags flags = 0xc33; /* fixme */ type = meta_frame_type_from_string (frame->type); if (type == META_FRAME_TYPE_LAST) return 1.0f; gfloat scale = meta_theme_get_title_scale (theme, type, flags); return scale; }
void meta_ui_theme_get_frame_borders (MetaUI *ui, MetaFrameType type, MetaFrameFlags flags, int *top_height, int *bottom_height, int *left_width, int *right_width) { int text_height; PangoContext *context; const PangoFontDescription *font_desc; GtkStyle *default_style; if (meta_ui_have_a_theme ()) { context = gtk_widget_get_pango_context (GTK_WIDGET (ui->frames)); font_desc = meta_prefs_get_titlebar_font (); if (!font_desc) { default_style = gtk_widget_get_default_style (); font_desc = default_style->font_desc; } text_height = meta_pango_font_desc_get_text_height (font_desc, context); meta_theme_get_frame_borders (meta_theme_get_current (), type, text_height, flags, top_height, bottom_height, left_width, right_width); } else { *top_height = *bottom_height = *left_width = *right_width = 0; } }
void meta_ui_theme_get_frame_borders (MetaUI *ui, MetaFrameType type, MetaFrameFlags flags, int *top_height, int *bottom_height, int *left_width, int *right_width) { int text_height; #if GTK_CHECK_VERSION (3, 0, 0) GtkStyleContext *style = NULL; PangoFontDescription *free_font_desc = NULL; #endif PangoContext *context; const PangoFontDescription *font_desc; if (meta_ui_have_a_theme ()) { context = gtk_widget_get_pango_context (GTK_WIDGET (ui->frames)); font_desc = meta_prefs_get_titlebar_font (); if (!font_desc) { #if GTK_CHECK_VERSION (3, 0, 0) GdkDisplay *display = gdk_x11_lookup_xdisplay (ui->xdisplay); GdkScreen *screen = gdk_display_get_screen (display, XScreenNumberOfScreen (ui->xscreen)); GtkWidgetPath *widget_path; style = gtk_style_context_new (); gtk_style_context_set_screen (style, screen); widget_path = gtk_widget_path_new (); gtk_widget_path_append_type (widget_path, GTK_TYPE_WINDOW); gtk_style_context_set_path (style, widget_path); gtk_widget_path_free (widget_path); gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, "font", &free_font_desc, NULL); font_desc = (const PangoFontDescription *) free_font_desc; #else GtkStyle *default_style; default_style = gtk_widget_get_default_style (); font_desc = default_style->font_desc; #endif } text_height = meta_pango_font_desc_get_text_height (font_desc, context); meta_theme_get_frame_borders (meta_theme_get_current (), type, text_height, flags, top_height, bottom_height, left_width, right_width); #if GTK_CHECK_VERSION (3, 0, 0) if (free_font_desc) pango_font_description_free (free_font_desc); #endif } else { *top_height = *bottom_height = *left_width = *right_width = 0; } #if GTK_CHECK_VERSION (3, 0, 0) if (style != NULL) g_object_unref (style); #endif }
gboolean meta_ui_have_a_theme (void) { return meta_theme_get_current () != NULL; }
gboolean meta_get_button_position (decor_t *d, gint i, gint width, gint height, gint *x, gint *y, gint *w, gint *h) { MetaButtonLayout button_layout; MetaFrameGeometry fgeom; MetaFrameFlags flags; MetaTheme *theme; GdkRectangle clip; MetaButtonSpace *space; gint mutter_draggable_border_width = 0; g_object_get (settings, "draggable-border-width", &mutter_draggable_border_width, NULL); if (!d->context) { /* undecorated windows implicitly have no buttons */ return FALSE; } theme = meta_theme_get_current (); meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout, meta_frame_type_from_string (d->frame->type), &clip); switch (i) { case BUTTON_MENU: if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_MENU)) return FALSE; space = &fgeom.menu_rect; break; case BUTTON_MIN: if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_MINIMIZE)) return FALSE; space = &fgeom.min_rect; break; case BUTTON_MAX: if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_MAXIMIZE)) return FALSE; space = &fgeom.max_rect; break; case BUTTON_CLOSE: if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_CLOSE)) return FALSE; space = &fgeom.close_rect; break; case BUTTON_SHADE: if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_SHADE)) return FALSE; space = &fgeom.shade_rect; break; case BUTTON_ABOVE: if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_ABOVE)) return FALSE; space = &fgeom.above_rect; break; case BUTTON_STICK: if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_STICK)) return FALSE; space = &fgeom.stick_rect; break; case BUTTON_UNSHADE: if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_UNSHADE)) return FALSE; space = &fgeom.unshade_rect; break; case BUTTON_UNABOVE: if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_UNABOVE)) return FALSE; space = &fgeom.unabove_rect; break; case BUTTON_UNSTICK: if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_UNSTICK)) return FALSE; space = &fgeom.unstick_rect; break; default: return FALSE; } if (!space->clickable.width && !space->clickable.height) return FALSE; *x = space->clickable.x; *y = space->clickable.y; *w = space->clickable.width; *h = space->clickable.height; if (d->frame_window) { *x += d->frame->win_extents.left + 4; *y += d->frame->win_extents.top + 2; } if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) { *x += mutter_draggable_border_width; } if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) { *y += mutter_draggable_border_width; } return TRUE; }
void meta_draw_window_decoration (decor_t *d) { Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); cairo_surface_t *surface; Picture src; MetaButtonState button_states [META_BUTTON_TYPE_LAST]; MetaButtonLayout button_layout; MetaFrameGeometry fgeom; MetaFrameFlags flags; MetaFrameType frame_type; MetaTheme *theme; GtkStyleContext *context; cairo_t *cr; gint i; GdkRectangle clip; Region top_region = NULL; Region bottom_region = NULL; Region left_region = NULL; Region right_region = NULL; gdouble meta_active_opacity, meta_inactive_opacity; gboolean meta_active_shade_opacity, meta_inactive_shade_opacity; g_object_get (settings, "metacity-active-opacity", &meta_active_opacity, NULL); g_object_get (settings, "metacity-inactive-opacity", &meta_inactive_opacity, NULL); g_object_get (settings, "metacity-active-shade-opacity", &meta_active_shade_opacity, NULL); g_object_get (settings, "metacity-inactive-shade-opacity", &meta_inactive_shade_opacity, NULL); double alpha = (d->active) ? meta_active_opacity : meta_inactive_opacity; gboolean shade_alpha = (d->active) ? meta_active_shade_opacity : meta_inactive_shade_opacity; MetaFrameStyle *frame_style; GtkWidget *style_window; GdkRGBA bg_rgba; if (!d->surface || !d->picture) return; if (decoration_alpha == 1.0) alpha = 1.0; if (cairo_xlib_surface_get_depth (d->surface) == 32) { context = gtk_widget_get_style_context (d->frame->style_window_rgba); style_window = d->frame->style_window_rgba; } else { context = gtk_widget_get_style_context (d->frame->style_window_rgb); style_window = d->frame->style_window_rgb; } cr = cairo_create (d->buffer_surface ? d->buffer_surface : d->surface); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); theme = meta_theme_get_current (); frame_type = meta_frame_type_from_string (d->frame->type); if (frame_type == META_FRAME_TYPE_LAST) frame_type = META_FRAME_TYPE_NORMAL; meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout, frame_type, &clip); if ((d->prop_xid || !d->buffer_surface) && !d->frame_window) draw_shadow_background (d, cr, d->shadow, d->context); for (i = 0; i < META_BUTTON_TYPE_LAST; ++i) button_states[i] = meta_button_state_for_button_type (d, i); frame_style = meta_theme_get_frame_style (theme, frame_type, flags); gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg_rgba); bg_rgba.alpha = 1.0; if (frame_style->window_background_color) { meta_color_spec_render (frame_style->window_background_color, gtk_widget_get_style_context (style_window), &bg_rgba); bg_rgba.alpha = frame_style->window_background_alpha / 255.0; } /* Draw something that will be almost invisible to user. This is hacky way * to fix invisible decorations. */ cairo_set_source_rgba (cr, 0, 0, 0, 0.01); cairo_rectangle (cr, 0, 0, 1, 1); cairo_fill (cr); /* ------------ */ cairo_destroy (cr); if (d->frame_window) surface = create_surface (clip.width, clip.height, d->frame->style_window_rgb); else surface = create_surface (clip.width, clip.height, d->frame->style_window_rgba); cr = cairo_create (surface); gdk_cairo_set_source_rgba (cr, &bg_rgba); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); src = XRenderCreatePicture (xdisplay, cairo_xlib_surface_get_drawable (surface), get_format_for_surface (d, surface), 0, NULL); cairo_paint (cr); meta_theme_draw_frame (theme, style_window, cr, frame_type, flags, clip.width - fgeom.left_width - fgeom.right_width, clip.height - fgeom.top_height - fgeom.bottom_height, d->layout, d->frame->text_height, &button_layout, button_states, d->icon_pixbuf, NULL); if (fgeom.top_height) { top_region = meta_get_top_border_region (&fgeom, clip.width); decor_blend_border_picture (xdisplay, d->context, src, 0, 0, d->picture, &d->border_layout, BORDER_TOP, top_region, alpha * 0xffff, shade_alpha, 0); } if (fgeom.bottom_height) { bottom_region = meta_get_bottom_border_region (&fgeom, clip.width); decor_blend_border_picture (xdisplay, d->context, src, 0, clip.height - fgeom.bottom_height, d->picture, &d->border_layout, BORDER_BOTTOM, bottom_region, alpha * 0xffff, shade_alpha, 0); } if (fgeom.left_width) { left_region = meta_get_left_border_region (&fgeom, clip.height); decor_blend_border_picture (xdisplay, d->context, src, 0, fgeom.top_height, d->picture, &d->border_layout, BORDER_LEFT, left_region, alpha * 0xffff, shade_alpha, 0); } if (fgeom.right_width) { right_region = meta_get_right_border_region (&fgeom, clip.height); decor_blend_border_picture (xdisplay, d->context, src, clip.width - fgeom.right_width, fgeom.top_height, d->picture, &d->border_layout, BORDER_RIGHT, right_region, alpha * 0xffff, shade_alpha, 0); } cairo_destroy (cr); cairo_surface_destroy (surface); XRenderFreePicture (xdisplay, src); copy_to_front_buffer (d); if (d->frame_window) { GdkWindow *gdk_frame_window = gtk_widget_get_window (d->decor_window); GdkPixbuf *pixbuf = gdk_pixbuf_get_from_surface (d->surface, 0, 0, d->width, d->height); gtk_image_set_from_pixbuf (GTK_IMAGE (d->decor_image), pixbuf); g_object_unref (pixbuf); gtk_window_resize (GTK_WINDOW (d->decor_window), d->width, d->height); gdk_window_move (gdk_frame_window, d->context->left_corner_space - 1, d->context->top_corner_space - 1); gdk_window_lower (gdk_frame_window); } if (d->prop_xid) { /* translate from frame to client window space */ if (top_region) XOffsetRegion (top_region, -fgeom.left_width, -fgeom.top_height); if (bottom_region) XOffsetRegion (bottom_region, -fgeom.left_width, 0); if (left_region) XOffsetRegion (left_region, -fgeom.left_width, 0); decor_update_meta_window_property (d, theme, flags, top_region, bottom_region, left_region, right_region); d->prop_xid = 0; } if (top_region) XDestroyRegion (top_region); if (bottom_region) XDestroyRegion (bottom_region); if (left_region) XDestroyRegion (left_region); if (right_region) XDestroyRegion (right_region); }
void meta_update_border_extents (decor_frame_t *frame) { MetaTheme *theme = meta_theme_get_current (); #ifdef HAVE_METACITY_3_14_0 MetaFrameBorders borders; #endif gwd_decor_frame_ref (frame); MetaFrameType frame_type = meta_frame_type_from_string (frame->type); gint top_height, bottom_height, left_width, right_width; if (!(frame_type < META_FRAME_TYPE_LAST)) frame_type = META_FRAME_TYPE_NORMAL; #ifdef HAVE_METACITY_3_14_0 meta_theme_get_frame_borders (theme, frame_type, frame->text_height, 0, &borders); top_height = borders.visible.top; bottom_height = borders.visible.bottom; left_width = borders.visible.left; right_width = borders.visible.right; #else meta_theme_get_frame_borders (theme, frame_type, frame->text_height, 0, &top_height, &bottom_height, &left_width, &right_width); #endif frame->win_extents.top = frame->win_extents.top; frame->win_extents.bottom = bottom_height; frame->win_extents.left = left_width; frame->win_extents.right = right_width; frame->titlebar_height = top_height - frame->win_extents.top; #ifdef HAVE_METACITY_3_14_0 meta_theme_get_frame_borders (theme, frame_type, frame->text_height, META_FRAME_MAXIMIZED, &borders); top_height = borders.visible.top; bottom_height = borders.visible.bottom; left_width = borders.visible.left; right_width = borders.visible.right; #else meta_theme_get_frame_borders (theme, frame_type, frame->text_height, META_FRAME_MAXIMIZED, &top_height, &bottom_height, &left_width, &right_width); #endif frame->max_win_extents.top = frame->win_extents.top; frame->max_win_extents.bottom = bottom_height; frame->max_win_extents.left = left_width; frame->max_win_extents.right = right_width; frame->max_titlebar_height = top_height - frame->max_win_extents.top; gwd_decor_frame_unref (frame); }
void meta_get_event_window_position (decor_t *d, gint i, gint j, gint width, gint height, gint *x, gint *y, gint *w, gint *h) { MetaButtonLayout button_layout; MetaFrameGeometry fgeom; MetaFrameFlags flags; MetaTheme *theme; GdkRectangle clip; gint mutter_draggable_border_width = 0; g_object_get (settings, "draggable-border-width", &mutter_draggable_border_width, NULL); theme = meta_theme_get_current (); meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout, meta_frame_type_from_string (d->frame->type), &clip); width += fgeom.right_width + fgeom.left_width; height += fgeom.top_height + fgeom.bottom_height; switch (i) { case 2: /* bottom */ switch (j) { case 2: /* bottom right */ if (d->frame_window) { *x = width - fgeom.right_width - RESIZE_EXTENDS + d->frame->win_extents.left + 2; *y = height - fgeom.bottom_height - RESIZE_EXTENDS + d->frame->win_extents.top + 2; } else { *x = width - fgeom.right_width - RESIZE_EXTENDS; *y = height - fgeom.bottom_height - RESIZE_EXTENDS; } *w = fgeom.right_width + RESIZE_EXTENDS; *h = fgeom.bottom_height + RESIZE_EXTENDS; if (!d->frame_window) { *x += mutter_draggable_border_width; *y += mutter_draggable_border_width; *w += mutter_draggable_border_width; *h += mutter_draggable_border_width; } break; case 1: /* bottom */ *x = fgeom.left_width + RESIZE_EXTENDS; *y = height - fgeom.bottom_height; if (d->frame_window) *y += d->frame->win_extents.top + 2; *w = width - fgeom.left_width - fgeom.right_width - (2 * RESIZE_EXTENDS); *h = fgeom.bottom_height; if (!d->frame_window) { *x -= mutter_draggable_border_width; *y += mutter_draggable_border_width; *h += mutter_draggable_border_width; *w += mutter_draggable_border_width * 2; } break; case 0: /* bottom left */ default: *x = 0; *y = height - fgeom.bottom_height - RESIZE_EXTENDS; if (d->frame_window) { *x += d->frame->win_extents.left + 4; *y += d->frame->win_extents.bottom + 2; } *w = fgeom.left_width + RESIZE_EXTENDS; *h = fgeom.bottom_height + RESIZE_EXTENDS; if (!d->frame_window) { *y += mutter_draggable_border_width; *w += mutter_draggable_border_width; *h += mutter_draggable_border_width; } break; } break; case 1: /* middle */ switch (j) { case 2: /* right */ *x = width - fgeom.right_width; *y = fgeom.top_height + RESIZE_EXTENDS; if (d->frame_window) *x += d->frame->win_extents.left + 2; *w = fgeom.right_width; *h = height - fgeom.top_height - fgeom.bottom_height - (2 * RESIZE_EXTENDS); if (!d->frame_window) { *x += mutter_draggable_border_width; *y += mutter_draggable_border_width; *w += mutter_draggable_border_width; *h += mutter_draggable_border_width; } break; case 1: /* middle */ *x = fgeom.left_width; *y = fgeom.title_rect.y + TOP_RESIZE_HEIGHT; *w = width - fgeom.left_width - fgeom.right_width; *h = height - fgeom.top_titlebar_edge - fgeom.bottom_height; if (!d->frame_window) { *x += mutter_draggable_border_width; if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) *y += mutter_draggable_border_width; } break; case 0: /* left */ default: *x = 0; if (d->frame_window) *x += d->frame->win_extents.left + 4; *y = fgeom.top_height + RESIZE_EXTENDS; *w = fgeom.left_width; *h = height - fgeom.top_height - fgeom.bottom_height - (2 * RESIZE_EXTENDS); if (!d->frame_window) { *y += mutter_draggable_border_width; *h += mutter_draggable_border_width; *w += mutter_draggable_border_width; } break; } break; case 0: /* top */ default: switch (j) { case 2: /* top right */ *x = width - fgeom.right_width - RESIZE_EXTENDS; *y = 0; if (d->frame_window) { *x += d->frame->win_extents.left + 2; *y += d->frame->win_extents.top + 2 - fgeom.title_rect.height; } *w = fgeom.right_width + RESIZE_EXTENDS; *h = fgeom.top_height + RESIZE_EXTENDS; if (!d->frame_window) { *x += mutter_draggable_border_width; *w += mutter_draggable_border_width; *h += mutter_draggable_border_width; } break; case 1: /* top */ *x = fgeom.left_width + RESIZE_EXTENDS; *y = 0; if (d->frame_window) *y += d->frame->win_extents.top + 2; *w = width - fgeom.left_width - fgeom.right_width - (2 * RESIZE_EXTENDS); *h = fgeom.title_rect.y + TOP_RESIZE_HEIGHT; if (!d->frame_window) { *x -= mutter_draggable_border_width; *w += mutter_draggable_border_width * 2; *h += mutter_draggable_border_width; } break; case 0: /* top left */ default: *x = 0; *y = 0; if (d->frame_window) { *x += d->frame->win_extents.left + 4; *y += d->frame->win_extents.top + 2 - fgeom.title_rect.height; } *w = fgeom.left_width + RESIZE_EXTENDS; *h = fgeom.top_height + RESIZE_EXTENDS; if (!d->frame_window) { *w += mutter_draggable_border_width; *h += mutter_draggable_border_width; } break; } } if (!(flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)) { /* turn off top and bottom event windows */ if (i == 0 || i == 2) *w = *h = 0; } if (!(flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)) { /* turn off left and right event windows */ if (j == 0 || j == 2) *w = *h = 0; } }