void popup_delay_show(ObPopup *self, gulong msec, gchar *text) { gint l, t, r, b; gint x, y, w, h; guint m; gint emptyx, emptyy; /* empty space between elements */ gint textx, texty, textw, texth; gint iconx, icony, iconw, iconh; const Rect *area; Rect mon; gboolean hasicon = self->hasicon; /* when there is no icon and the text is not parent relative, then fill the whole dialog with the text appearance, don't use the bg at all */ if (hasicon || self->a_text->surface.grad == RR_SURFACE_PARENTREL) RrMargins(self->a_bg, &l, &t, &r, &b); else l = t = r = b = 0; /* set up the textures */ self->a_text->texture[0].data.text.string = text; /* measure the text out */ if (text[0] != '\0') { RrMinSize(self->a_text, &textw, &texth); } else { textw = 0; texth = RrMinHeight(self->a_text); } /* get the height, which is also used for the icon width */ emptyy = t + b + ob_rr_theme->paddingy * 2; if (self->h) texth = self->h - emptyy; h = texth * self->iconhm + emptyy; if (self->textw) textw = self->textw; iconx = textx = l + ob_rr_theme->paddingx; emptyx = l + r + ob_rr_theme->paddingx * 2; if (hasicon) { iconw = texth * self->iconwm; iconh = texth * self->iconhm; textx += iconw + ob_rr_theme->paddingx; if (textw) emptyx += ob_rr_theme->paddingx; /* between the icon and text */ icony = (h - iconh - emptyy) / 2 + t + ob_rr_theme->paddingy; } else iconw = 0; texty = (h - texth - emptyy) / 2 + t + ob_rr_theme->paddingy; /* when there is no icon, then fill the whole dialog with the text appearance */ if (!hasicon) { textx = texty = 0; texth += emptyy; textw += emptyx; emptyx = emptyy = 0; } w = textw + emptyx + iconw; /* cap it at maxw/minw */ if (self->maxw) w = MIN(w, self->maxw); if (self->minw) w = MAX(w, self->minw); textw = w - emptyx - iconw; /* sanity checks to avoid crashes! */ if (w < 1) w = 1; if (h < 1) h = 1; if (texth < 1) texth = 1; /* set up the x coord */ x = self->x; switch (self->gravity) { case NorthGravity: case CenterGravity: case SouthGravity: x -= w / 2; break; case NorthEastGravity: case EastGravity: case SouthEastGravity: x -= w; break; } /* set up the y coord */ y = self->y; switch (self->gravity) { case WestGravity: case CenterGravity: case EastGravity: y -= h / 2; break; case SouthWestGravity: case SouthGravity: case SouthEastGravity: y -= h; break; } /* Find the monitor which contains the biggest part of the popup. * If the popup is completely off screen, limit it to the intersection * of all monitors and then try again. If it's still off screen, put it * on monitor 0. */ RECT_SET(mon, x, y, w, h); m = screen_find_monitor(&mon); area = screen_physical_area_monitor(m); x=MAX(MIN(x, area->x+area->width-w),area->x); y=MAX(MIN(y, area->y+area->height-h),area->y); if (m == screen_num_monitors) { RECT_SET(mon, x, y, w, h); m = screen_find_monitor(&mon); if (m == screen_num_monitors) m = 0; area = screen_physical_area_monitor(m); x=MAX(MIN(x, area->x+area->width-w),area->x); y=MAX(MIN(y, area->y+area->height-h),area->y); } /* set the windows/appearances up */ XMoveResizeWindow(obt_display, self->bg, x, y, w, h); /* when there is no icon and the text is not parent relative, then fill the whole dialog with the text appearance, don't use the bg at all */ if (hasicon || self->a_text->surface.grad == RR_SURFACE_PARENTREL) RrPaint(self->a_bg, self->bg, w, h); if (textw) { self->a_text->surface.parent = self->a_bg; self->a_text->surface.parentx = textx; self->a_text->surface.parenty = texty; XMoveResizeWindow(obt_display, self->text, textx, texty, textw, texth); RrPaint(self->a_text, self->text, textw, texth); } if (hasicon) self->draw_icon(iconx, icony, iconw, iconh, self->draw_icon_data); /* do the actual showing */ if (!self->mapped) { if (msec) { /* don't kill previous show timers */ if (!self->delay_mapped) { self->delay_timer = g_timeout_add(msec, popup_show_timeout, self); self->delay_mapped = TRUE; } } else { popup_show_timeout(self); } } }
/* XXX: Make this more general */ static GdkPixbuf* preview_menu(RrTheme *theme) { RrAppearance *title; RrAppearance *title_text; RrAppearance *menu; RrAppearance *background; RrAppearance *normal; RrAppearance *disabled; RrAppearance *selected; RrAppearance *bullet; /* for submenu */ GdkPixmap *pixmap; GdkPixbuf *pixbuf; /* width and height of the whole menu */ gint width, height; gint x, y; gint title_h; gint tw, th; gint bw, bh; gint unused; /* set up appearances */ title = theme->a_menu_title; title_text = theme->a_menu_text_title; title_text->surface.parent = title; title_text->texture[0].data.text.string = "Menu"; normal = theme->a_menu_text_normal; normal->texture[0].data.text.string = "Normal"; disabled = theme->a_menu_text_disabled; disabled->texture[0].data.text.string = "Disabled"; selected = theme->a_menu_text_selected; selected->texture[0].data.text.string = "Selected"; bullet = theme->a_menu_bullet_normal; /* determine window size */ RrMinSize(normal, &width, &th); width += th + PADDING; /* make space for the bullet */ //height = th; width += 2*theme->mbwidth + 2*PADDING; /* get minimum title size */ RrMinSize(title, &tw, &title_h); /* size of background behind each text line */ bw = width - 2*theme->mbwidth; //title_h += 2*PADDING; title_h = theme->menu_title_height; RrMinSize(normal, &unused, &th); bh = th + 2*PADDING; height = title_h + 3*bh + 3*theme->mbwidth; //height += 3*th + 3*theme->mbwidth + 5*PADDING; /* set border */ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height); gdk_pixbuf_fill(pixbuf, rr_color_pixel(theme->menu_border_color)); /* draw title */ x = y = theme->mbwidth; theme_pixmap_paint(title, bw, title_h); /* draw title text */ title_text->surface.parentx = 0; title_text->surface.parenty = 0; theme_pixmap_paint(title_text, bw, title_h); pixmap = gdk_pixmap_foreign_new(title_text->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, bw, title_h); /* menu appears after title */ y += theme->mbwidth + title_h; /* fill in menu appearance, used as the parent to every menu item's bg */ menu = theme->a_menu; th = height - 3*theme->mbwidth - title_h; theme_pixmap_paint(menu, bw, th); pixmap = gdk_pixmap_foreign_new(menu->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, bw, th); /* fill in background appearance, used as the parent to text items */ background = theme->a_menu_normal; background->surface.parent = menu; background->surface.parentx = 0; background->surface.parenty = 0; /* draw background for normal entry */ theme_pixmap_paint(background, bw, bh); pixmap = gdk_pixmap_foreign_new(background->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, bw, bh); /* draw normal entry */ normal->surface.parent = background; normal->surface.parentx = PADDING; normal->surface.parenty = PADDING; x += PADDING; y += PADDING; RrMinSize(normal, &tw, &th); theme_pixmap_paint(normal, tw, th); pixmap = gdk_pixmap_foreign_new(normal->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, tw, th); /* draw bullet */ RrMinSize(normal, &tw, &th); bullet->surface.parent = background; bullet->surface.parentx = bw - th; bullet->surface.parenty = PADDING; theme_pixmap_paint(bullet, th, th); pixmap = gdk_pixmap_foreign_new(bullet->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, width - theme->mbwidth - th, y, th, th); y += th + 2*PADDING; /* draw background for disabled entry */ background->surface.parenty = bh; theme_pixmap_paint(background, bw, bh); pixmap = gdk_pixmap_foreign_new(background->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x - PADDING, y - PADDING, bw, bh); /* draw disabled entry */ RrMinSize(disabled, &tw, &th); disabled->surface.parent = background; disabled->surface.parentx = PADDING; disabled->surface.parenty = PADDING; theme_pixmap_paint(disabled, tw, th); pixmap = gdk_pixmap_foreign_new(disabled->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, tw, th); y += th + 2*PADDING; /* draw background for selected entry */ background = theme->a_menu_selected; background->surface.parent = menu; background->surface.parentx = 2*bh; theme_pixmap_paint(background, bw, bh); pixmap = gdk_pixmap_foreign_new(background->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x - PADDING, y - PADDING, bw, bh); /* draw selected entry */ RrMinSize(selected, &tw, &th); selected->surface.parent = background; selected->surface.parentx = PADDING; selected->surface.parenty = PADDING; theme_pixmap_paint(selected, tw, th); pixmap = gdk_pixmap_foreign_new(selected->pixmap); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_colormap_get_system(), 0, 0, x, y, tw, th); return pixbuf; }
static void prompt_layout(ObPrompt *self) { gint l, r, t, b; gint i; gint allbuttonsw, allbuttonsh, buttonx; gint w, h; gint maxw; RrMargins(prompt_a_bg, &l, &t, &r, &b); l += OUTSIDE_MARGIN; t += OUTSIDE_MARGIN; r += OUTSIDE_MARGIN; b += OUTSIDE_MARGIN; { const Rect *area = screen_physical_area_all_monitors(); maxw = MIN(MAX_WIDTH, area->width*4/5); } /* find the button sizes and how much space we need for them */ allbuttonsw = allbuttonsh = 0; for (i = 0; i < self->n_buttons; ++i) { gint bw, bh; prompt_a_button->texture[0].data.text.string = self->button[i].text; prompt_a_focus->texture[0].data.text.string = self->button[i].text; prompt_a_press->texture[0].data.text.string = self->button[i].text; prompt_a_pfocus->texture[0].data.text.string = self->button[i].text; RrMinSize(prompt_a_button, &bw, &bh); self->button[i].width = bw; self->button[i].height = bh; RrMinSize(prompt_a_focus, &bw, &bh); self->button[i].width = MAX(self->button[i].width, bw); self->button[i].height = MAX(self->button[i].height, bh); RrMinSize(prompt_a_press, &bw, &bh); self->button[i].width = MAX(self->button[i].width, bw); self->button[i].height = MAX(self->button[i].height, bh); RrMinSize(prompt_a_pfocus, &bw, &bh); self->button[i].width = MAX(self->button[i].width, bw); self->button[i].height = MAX(self->button[i].height, bh); self->button[i].width += BUTTON_HMARGIN * 2; self->button[i].height += BUTTON_VMARGIN * 2; allbuttonsw += self->button[i].width + (i > 0 ? BUTTON_SEPARATION : 0); allbuttonsh = MAX(allbuttonsh, self->button[i].height); } self->msg_wbound = MAX(allbuttonsw, maxw); /* measure the text message area */ prompt_a_msg->texture[0].data.text.string = self->msg.text; prompt_a_msg->texture[0].data.text.maxwidth = self->msg_wbound; RrMinSize(prompt_a_msg, &self->msg.width, &self->msg.height); /* width and height inside the outer margins */ w = MAX(self->msg.width, allbuttonsw); h = self->msg.height + MSG_BUTTON_SEPARATION + allbuttonsh; /* position the text message */ self->msg.x = l + (w - self->msg.width) / 2; self->msg.y = t; /* position the button buttons on the right of the dialog */ buttonx = l + w; for (i = self->n_buttons - 1; i >= 0; --i) { self->button[i].x = buttonx - self->button[i].width; buttonx -= self->button[i].width + BUTTON_SEPARATION; self->button[i].y = t + h - allbuttonsh; self->button[i].y += (allbuttonsh - self->button[i].height) / 2; } /* size and position the toplevel window */ prompt_resize(self, w + l + r, h + t + b); /* move and resize the internal windows */ XMoveResizeWindow(obt_display, self->msg.window, self->msg.x, self->msg.y, self->msg.width, self->msg.height); for (i = 0; i < self->n_buttons; ++i) XMoveResizeWindow(obt_display, self->button[i].window, self->button[i].x, self->button[i].y, self->button[i].width, self->button[i].height); }
/* XXX: Make this more general */ static GdkPixbuf* preview_menu(RrTheme *theme) { RrAppearance *title; RrAppearance *title_text; RrAppearance *menu; RrAppearance *background; RrAppearance *normal; RrAppearance *disabled; RrAppearance *selected; RrAppearance *bullet; /* for submenu */ cairo_surface_t *surface; GdkScreen *screen; Display *xdisplay; Visual *xvisual; GdkPixbuf *pixbuf, *tmp_pixbuf; /* width and height of the whole menu */ gint width, height; gint x, y; gint title_h; gint tw, th; gint bw, bh; gint unused; screen = gdk_screen_get_default(); xdisplay = gdk_x11_get_default_xdisplay(); xvisual = gdk_x11_visual_get_xvisual(gdk_screen_get_system_visual(screen)); /* set up appearances */ title = theme->a_menu_title; title_text = theme->a_menu_text_title; title_text->surface.parent = title; title_text->texture[0].data.text.string = "Menu"; normal = theme->a_menu_text_normal; normal->texture[0].data.text.string = "Normal"; disabled = theme->a_menu_text_disabled; disabled->texture[0].data.text.string = "Disabled"; selected = theme->a_menu_text_selected; selected->texture[0].data.text.string = "Selected"; bullet = theme->a_menu_bullet_normal; /* determine window size */ RrMinSize(normal, &width, &th); width += th + PADDING; /* make space for the bullet */ width += 2*theme->mbwidth + 2*PADDING; /* get minimum title size */ RrMinSize(title, &tw, &title_h); /* size of background behind each text line */ bw = width - 2*theme->mbwidth; //title_h += 2*PADDING; title_h = theme->menu_title_height; RrMinSize(normal, &unused, &th); bh = th + 2*PADDING; height = title_h + 3*bh + 3*theme->mbwidth; /* set border */ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height); gdk_pixbuf_fill(pixbuf, rr_color_pixel(theme->menu_border_color)); tmp_pixbuf = gdk_pixbuf_copy(pixbuf); /* menu appears after inside the border */ x = y = theme->mbwidth; /* fill in menu appearance, used as the parent to every menu item's bg */ menu = theme->a_menu; th = height - 2 * theme->mbwidth; theme_pixmap_paint(menu, bw, th); /* draw title, it appears at the top of the menu background */ title->surface.parent = theme->a_menu; title->surface.parentx = 0; title->surface.parenty = 0; theme_pixmap_paint(title, bw, title_h); /* draw title text */ title_text->surface.parentx = 0; title_text->surface.parenty = 0; theme_pixmap_paint(title_text, bw, title_h); surface = cairo_xlib_surface_create(xdisplay, title_text->pixmap, xvisual, bw, title_h); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, bw, title_h); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, bw, title_h, pixbuf, x, y); y += title_h + theme->mbwidth; /* fill in background appearance, used as the parent to text items */ background = theme->a_menu_normal; background->surface.parent = menu; background->surface.parentx = x - theme->mbwidth; background->surface.parenty = y - theme->mbwidth; /* draw background for normal entry */ theme_pixmap_paint(background, bw, bh); surface = cairo_xlib_surface_create(xdisplay, background->pixmap, xvisual, bw, bh); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, bw, bh); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, bw, bh, pixbuf, x, y); /* draw normal entry */ normal->surface.parent = background; normal->surface.parentx = PADDING; normal->surface.parenty = PADDING; RrMinSize(normal, &tw, &th); theme_pixmap_paint(normal, tw, th); surface = cairo_xlib_surface_create(xdisplay, normal->pixmap, xvisual, tw, th); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, tw, th); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, tw, th, pixbuf, x + PADDING, y + PADDING); /* draw bullet */ RrMinSize(normal, &tw, &th); bullet->surface.parent = background; bullet->surface.parentx = bw - th; bullet->surface.parenty = PADDING; theme_pixmap_paint(bullet, th, th); surface = cairo_xlib_surface_create(xdisplay, bullet->pixmap, xvisual, th, th); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, th, th); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, th, th, pixbuf, width - theme->mbwidth - th, y + PADDING); y += th + 2*PADDING; /* draw background for disabled entry */ background->surface.parent = menu; background->surface.parentx = x - theme->mbwidth; background->surface.parenty = y - theme->mbwidth; theme_pixmap_paint(background, bw, bh); surface = cairo_xlib_surface_create(xdisplay, background->pixmap, xvisual, bw, bh); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, bw, bh); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, bw, bh, pixbuf, x, y); /* draw disabled entry */ RrMinSize(disabled, &tw, &th); disabled->surface.parent = background; disabled->surface.parentx = PADDING; disabled->surface.parenty = PADDING; theme_pixmap_paint(disabled, tw, th); surface = cairo_xlib_surface_create(xdisplay, disabled->pixmap, xvisual, tw, th); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, tw, th); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, tw, th, pixbuf, x + PADDING, y + PADDING); y += th + 2*PADDING; /* draw background for selected entry */ background = theme->a_menu_selected; background->surface.parent = menu; background->surface.parentx = x - theme->mbwidth; background->surface.parenty = y - theme->mbwidth; theme_pixmap_paint(background, bw, bh); surface = cairo_xlib_surface_create(xdisplay, background->pixmap, xvisual, bw, bh); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, bw, bh); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, bw, bh, pixbuf, x, y); /* draw selected entry */ RrMinSize(selected, &tw, &th); selected->surface.parent = background; selected->surface.parentx = PADDING; selected->surface.parenty = PADDING; theme_pixmap_paint(selected, tw, th); surface = cairo_xlib_surface_create(xdisplay, selected->pixmap, xvisual, tw, th); tmp_pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, tw, th); cairo_surface_destroy(surface); gdk_pixbuf_copy_area(tmp_pixbuf, 0, 0, tw, th, pixbuf, x + PADDING, y + PADDING); g_object_unref(tmp_pixbuf); return pixbuf; }