void menu_frame_move_on_screen(ObMenuFrame *self, gint x, gint y, gint *dx, gint *dy) { const Rect *a = NULL; Rect search = self->area; gint pos, half, monitor; *dx = *dy = 0; RECT_SET_POINT(search, x, y); if (self->parent) monitor = self->parent->monitor; else monitor = screen_find_monitor(&search); a = screen_physical_area_monitor(monitor); half = g_list_length(self->entries) / 2; pos = g_list_index(self->entries, self->selected); /* if in the bottom half then check this stuff first, will keep the bottom edge of the menu visible */ if (pos > half) { *dx = MAX(*dx, a->x - x); *dy = MAX(*dy, a->y - y); } *dx = MIN(*dx, (a->x + a->width) - (x + self->area.width)); *dy = MIN(*dy, (a->y + a->height) - (y + self->area.height)); /* if in the top half then check this stuff last, will keep the top edge of the menu visible */ if (pos <= half) { *dx = MAX(*dx, a->x - x); *dy = MAX(*dy, a->y - y); } }
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); } } }