}
}
+static void client_menu_place(ObMenuFrame *frame, gint *x, gint *y,
+ gint button, gpointer data)
+{
+ gint dx, dy;
+
+ if (button == 0 && frame->client) {
+ *x = frame->client->frame->area.x;
+
+ /* try below the titlebar */
+ *y = frame->client->frame->area.y + frame->client->frame->size.top -
+ frame->client->frame->bwidth;
+ menu_frame_move_on_screen(frame, *x, *y, &dx, &dy);
+ if (dy != 0) {
+ /* try above the titlebar */
+ *y = frame->client->frame->area.y + frame->client->frame->bwidth -
+ frame->area.height;
+ menu_frame_move_on_screen(frame, *x, *y, &dx, &dy);
+ }
+ if (dy != 0) {
+ /* didnt fit either way, use move on screen's values */
+ *y = frame->client->frame->area.y + frame->client->frame->size.top;
+ menu_frame_move_on_screen(frame, *x, *y, &dx, &dy);
+ }
+
+ *x += dx;
+ *y += dy;
+ } else {
+ gint myx, myy;
+
+ myx = *x;
+ myy = *y;
+
+ /* try to the bottom right of the cursor */
+ menu_frame_move_on_screen(frame, myx, myy, &dx, &dy);
+ if (dx != 0 || dy != 0) {
+ /* try to the bottom left of the cursor */
+ myx = *x - frame->area.width;
+ myy = *y;
+ menu_frame_move_on_screen(frame, myx, myy, &dx, &dy);
+ }
+ if (dx != 0 || dy != 0) {
+ /* try to the top right of the cursor */
+ myx = *x;
+ myy = *y - frame->area.height;
+ menu_frame_move_on_screen(frame, myx, myy, &dx, &dy);
+ }
+ if (dx != 0 || dy != 0) {
+ /* try to the top left of the cursor */
+ myx = *x - frame->area.width;
+ myy = *y - frame->area.height;
+ menu_frame_move_on_screen(frame, myx, myy, &dx, &dy);
+ }
+ if (dx != 0 || dy != 0) {
+ /* if didnt fit on either side so just use what it says */
+ myx = *x;
+ myy = *y;
+ menu_frame_move_on_screen(frame, myx, myy, &dx, &dy);
+ }
+ *x = myx + dx;
+ *y = myy + dy;
+ }
+}
+
void client_menu_startup()
{
GSList *acts;
menu = menu_new(CLIENT_MENU_NAME, _("Client menu"), TRUE, NULL);
menu_show_all_shortcuts(menu, TRUE);
menu_set_update_func(menu, client_update);
+ menu_set_place_func(menu, client_menu_place);
menu_add_submenu(menu, CLIENT_SEND_TO, SEND_TO_MENU_NAME);
typedef void (*ObMenuExecuteFunc)(struct _ObMenuEntry *entry,
guint state, gpointer data, Time time);
typedef void (*ObMenuDestroyFunc)(struct _ObMenu *menu, gpointer data);
+/*! @param x is the mouse x coordinate. on return it should be the x coordinate
+ for the menu
+ @param y is the mouse y coordinate. on return it should be the y coordinate
+ for the menu
+*/
+typedef void (*ObMenuPlaceFunc)(struct _ObMenuFrame *frame, gint *x, gint *y,
+ gint button, gpointer data);
struct _ObMenu
{
ObMenuUpdateFunc update_func;
ObMenuExecuteFunc execute_func;
ObMenuDestroyFunc destroy_func;
+ ObMenuPlaceFunc place_func;
/* Pipe-menu parent, we get destroyed when it is destroyed */
ObMenu *pipe_creator;
void menu_show_all_shortcuts(ObMenu *self, gboolean show);
-void menu_show(gchar *name, gint x, gint y, struct _ObClient *client);
+void menu_show(gchar *name, gint x, gint y, gint button,
+ struct _ObClient *client);
void menu_set_update_func(ObMenu *menu, ObMenuUpdateFunc func);
void menu_set_execute_func(ObMenu *menu, ObMenuExecuteFunc func);
void menu_set_destroy_func(ObMenu *menu, ObMenuDestroyFunc func);
+void menu_set_place_func(ObMenu *menu, ObMenuPlaceFunc func);
/* functions for building menus */
/*! @param allow_shortcut this should be false when the label is coming from
XMoveWindow(ob_display, self->window, self->area.x, self->area.y);
}
-void menu_frame_place_topmenu(ObMenuFrame *self, gint x, gint y)
+static void menu_frame_place_topmenu(ObMenuFrame *self, gint *x, gint *y)
{
- if (self->client && x < 0 && y < 0) {
- x = self->client->frame->area.x + self->client->frame->size.left;
- y = self->client->frame->area.y + self->client->frame->size.top;
+ gint dx, dy;
+
+ if (config_menu_middle) {
+ gint myx;
+
+ myx = *x;
+ *y -= self->area.height / 2;
+
+ /* try to the right of the cursor */
+ menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+ if (dx != 0) {
+ /* try to the left of the cursor */
+ myx = *x - self->area.width;
+ menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+ }
+ if (dx != 0) {
+ /* if didnt fit on either side so just use what it says */
+ myx = *x;
+ menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+ }
+ *x = myx + dx;
+ *y += dy;
} else {
- if (config_menu_middle)
- y -= self->area.height / 2;
+ gint myx, myy;
+
+ myx = *x;
+ myy = *y;
+
+ /* try to the bottom right of the cursor */
+ menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+ if (dx != 0 || dy != 0) {
+ /* try to the bottom left of the cursor */
+ myx = *x - self->area.width;
+ myy = *y;
+ menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+ }
+ if (dx != 0 || dy != 0) {
+ /* try to the top right of the cursor */
+ myx = *x;
+ myy = *y - self->area.height;
+ menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+ }
+ if (dx != 0 || dy != 0) {
+ /* try to the top left of the cursor */
+ myx = *x - self->area.width;
+ myy = *y - self->area.height;
+ menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+ }
+ if (dx != 0 || dy != 0) {
+ /* if didnt fit on either side so just use what it says */
+ myx = *x;
+ myy = *y;
+ menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+ }
+ *x = myx + dx;
+ *y = myy + dy;
}
- menu_frame_move(self, x, y);
}
-void menu_frame_place_submenu(ObMenuFrame *self)
+static void menu_frame_place_submenu(ObMenuFrame *self, gint *x, gint *y)
{
- gint x, y;
gint overlap;
gint bwidth;
bwidth = ob_rr_theme->mbwidth;
if (self->direction_right)
- x = self->parent->area.x + self->parent->area.width - overlap - bwidth;
+ *x = self->parent->area.x + self->parent->area.width -
+ overlap - bwidth;
else
- x = self->parent->area.x - self->area.width + overlap + bwidth;
+ *x = self->parent->area.x - self->area.width + overlap + bwidth;
- y = self->parent->area.y + self->parent_entry->area.y;
+ *y = self->parent->area.y + self->parent_entry->area.y;
if (config_menu_middle)
- y -= (self->area.height - (bwidth * 2) - self->item_h) / 2;
+ *y -= (self->area.height - (bwidth * 2) - self->item_h) / 2;
else
- y += overlap;
-
- menu_frame_move(self, x, y);
+ *y += overlap;
}
-void menu_frame_move_on_screen(ObMenuFrame *self, gint *dx, gint *dy)
+void menu_frame_move_on_screen(ObMenuFrame *self, gint x, gint y,
+ gint *dx, gint *dy)
{
Rect *a = NULL;
gint pos, half;
/* 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 - self->area.x);
- *dy = MAX(*dy, a->y - self->area.y);
+ *dx = MAX(*dx, a->x - x);
+ *dy = MAX(*dy, a->y - y);
}
- *dx = MIN(*dx, (a->x + a->width) - (self->area.x + self->area.width));
- *dy = MIN(*dy, (a->y + a->height) - (self->area.y + self->area.height));
+ *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 - self->area.x);
- *dy = MAX(*dy, a->y - self->area.y);
+ *dx = MAX(*dx, a->x - x);
+ *dy = MAX(*dy, a->y - y);
}
}
return TRUE;
}
-gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y)
+gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y,
+ gint button)
{
- gint dx, dy;
guint i;
if (menu_frame_is_visible(self))
if (!menu_frame_show(self))
return FALSE;
- menu_frame_place_topmenu(self, x, y);
-
/* find the monitor the menu is on */
for (i = 0; i < screen_num_monitors; ++i) {
Rect *a = screen_physical_area_monitor(i);
}
}
- menu_frame_move_on_screen(self, &dx, &dy);
- menu_frame_move(self, self->area.x + dx, self->area.y + dy);
+ if (self->menu->place_func)
+ self->menu->place_func(self, &x, &y, button, self->menu->data);
+ else
+ menu_frame_place_topmenu(self, &x, &y);
+
+ menu_frame_move(self, x, y);
XMapWindow(ob_display, self->window);
ObMenuEntryFrame *parent_entry)
{
ObMenuEntryFrame *e;
- gint dx, dy;
+ gint x, y, dx, dy;
if (menu_frame_is_visible(self))
return TRUE;
if (!menu_frame_show(self))
return FALSE;
- menu_frame_place_submenu(self);
- menu_frame_move_on_screen(self, &dx, &dy);
-
- if (dx == 0) {
- menu_frame_move(self, self->area.x, self->area.y + dy);
- } else {
- gboolean dir;
+ menu_frame_place_submenu(self, &x, &y);
+ menu_frame_move_on_screen(self, x, y, &dx, &dy);
- /* flip the direction in which we're placing submenus */
- if (dx > 0)
- dir = TRUE;
- else
- dir = FALSE;
-
- /* if it changed, then replace the menu on the opposite side,
- and try keep it on the screen too */
- if (dir != self->direction_right) {
- self->direction_right = dir;
- menu_frame_place_submenu(self);
- menu_frame_move_on_screen(self, &dx, &dy);
- menu_frame_move(self, self->area.x + dx, self->area.y + dy);
- }
+ if (dx != 0) {
+ /*try the other side */
+ self->direction_right = !self->direction_right;
+ menu_frame_place_submenu(self, &x, &y);
+ menu_frame_move_on_screen(self, x, y, &dx, &dy);
}
+ menu_frame_move(self, x + dx, y + dy);
XMapWindow(ob_display, self->window);