/**************************************************************************** * Functions for handling window menus. * Copyright (C) 2004 Joe Wingbermuehle ****************************************************************************/ #include "jwm.h" #include "winmenu.h" #include "client.h" #include "menu.h" #include "main.h" #include "desktop.h" #include "move.h" #include "resize.h" #include "event.h" #include "cursor.h" #include "misc.h" static const char *SENDTO_TEXT = "Send To"; static const char *LAYER_TEXT = "Layer"; static Menu *CreateWindowMenu(); static void RunWindowCommand(const MenuAction *action); static void CreateWindowLayerMenu(Menu *menu); static void CreateWindowSendToMenu(Menu *menu); static void AddWindowMenuItem(Menu *menu, const char *name, MenuActionType type, int value); static ClientNode *client = NULL; /**************************************************************************** ****************************************************************************/ void GetWindowMenuSize(ClientNode *np, int *width, int *height) { Menu *menu; client = np; menu = CreateWindowMenu(); InitializeMenu(menu); *width = menu->width; *height = menu->height; DestroyMenu(menu); } /**************************************************************************** ****************************************************************************/ void ShowWindowMenu(ClientNode *np, int x, int y) { Menu *menu; client = np; menu = CreateWindowMenu(); InitializeMenu(menu); ShowMenu(menu, RunWindowCommand, x, y); DestroyMenu(menu); } /**************************************************************************** ****************************************************************************/ Menu * CreateWindowMenu() { Menu *menu; menu = Allocate(sizeof(Menu)); menu->itemHeight = 0; menu->items = NULL; menu->label = NULL; /* Note that items are added in reverse order of display. */ if(!(client->state.status & STAT_WMDIALOG)) { AddWindowMenuItem(menu, "Close", MA_CLOSE, 0); AddWindowMenuItem(menu, "Kill", MA_KILL, 0); AddWindowMenuItem(menu, NULL, MA_NONE, 0); } if(client->state.status & (STAT_MAPPED | STAT_SHADED)) { if(client->state.border & BORDER_RESIZE) { AddWindowMenuItem(menu, "Resize", MA_RESIZE, 0); } if(client->state.border & BORDER_MOVE) { AddWindowMenuItem(menu, "Move", MA_MOVE, 0); } } if(client->state.border & BORDER_MIN) { if(client->state.status & STAT_MINIMIZED) { AddWindowMenuItem(menu, "Restore", MA_RESTORE, 0); } else { if(client->state.status & STAT_SHADED) { AddWindowMenuItem(menu, "Unshade", MA_SHADE, 0); } else { AddWindowMenuItem(menu, "Shade", MA_SHADE, 0); } AddWindowMenuItem(menu, "Minimize", MA_MINIMIZE, 0); } } if((client->state.border & BORDER_MAX) && (client->state.status & STAT_MAPPED)) { AddWindowMenuItem(menu, "Maximize", MA_MAXIMIZE, 0); } if(!(client->state.status & STAT_WMDIALOG)) { if(client->state.status & STAT_STICKY) { AddWindowMenuItem(menu, "Unstick", MA_STICK, 0); } else { AddWindowMenuItem(menu, "Stick", MA_STICK, 0); } CreateWindowLayerMenu(menu); if(!(client->state.status & STAT_STICKY)) { CreateWindowSendToMenu(menu); } } return menu; } /**************************************************************************** ****************************************************************************/ void CreateWindowLayerMenu(Menu *menu) { Menu *submenu; MenuItem *item; char str[10]; unsigned int x; item = Allocate(sizeof(MenuItem)); item->type = MENU_ITEM_SUBMENU; item->name = CopyString(LAYER_TEXT); item->action.type = MA_NONE; item->action.data.str = NULL; item->iconName = NULL; item->next = menu->items; menu->items = item; submenu = Allocate(sizeof(Menu)); item->submenu = submenu; submenu->itemHeight = 0; submenu->items = NULL; submenu->label = NULL; if(client->state.layer == LAYER_TOP) { AddWindowMenuItem(submenu, "[Top]", MA_LAYER, LAYER_TOP); } else { AddWindowMenuItem(submenu, "Top", MA_LAYER, LAYER_TOP); } str[4] = 0; for(x = LAYER_TOP - 1; x > LAYER_BOTTOM; x--) { if(x == LAYER_NORMAL) { if(client->state.layer == x) { AddWindowMenuItem(submenu, "[Normal]", MA_LAYER, x); } else { AddWindowMenuItem(submenu, "Normal", MA_LAYER, x); } } else { if(client->state.layer == x) { str[0] = '['; str[3] = ']'; } else { str[0] = ' '; str[3] = ' '; } if(x < 10) { str[1] = ' '; } else { str[1] = (x / 10) + '0'; } str[2] = (x % 10) + '0'; AddWindowMenuItem(submenu, str, MA_LAYER, x); } } if(client->state.layer == LAYER_BOTTOM) { AddWindowMenuItem(submenu, "[Bottom]", MA_LAYER, LAYER_BOTTOM); } else { AddWindowMenuItem(submenu, "Bottom", MA_LAYER, LAYER_BOTTOM); } } /**************************************************************************** ****************************************************************************/ void CreateWindowSendToMenu(Menu *menu) { unsigned int mask; unsigned int x; mask = 0; for(x = 0; x < desktopCount; x++) { if(client->state.desktop == x || (client->state.status & STAT_STICKY)) { mask |= 1 << x; } } AddWindowMenuItem(menu, SENDTO_TEXT, MA_NONE, 0); /* Now the first item in the menu is for the desktop list. */ menu->items->submenu = CreateDesktopMenu(mask); } /**************************************************************************** ****************************************************************************/ void AddWindowMenuItem(Menu *menu, const char *name, MenuActionType type, int value) { MenuItem *item; item = Allocate(sizeof(MenuItem)); if(name) { item->type = MENU_ITEM_NORMAL; } else { item->type = MENU_ITEM_SEPARATOR; } item->name = CopyString(name); item->action.type = type; item->action.data.i = value; item->iconName = NULL; item->submenu = NULL; item->next = menu->items; menu->items = item; } /**************************************************************************** ****************************************************************************/ void ChooseWindow(const MenuAction *action) { XEvent event; ClientNode *np; GrabMouseForChoose(); for(;;) { WaitForEvent(&event); if(event.type == ButtonPress) { if(event.xbutton.button == Button1) { np = FindClientByWindow(event.xbutton.subwindow); if(np) { client = np; RunWindowCommand(action); } } break; } else if(event.type == KeyPress) { break; } } JXUngrabPointer(display, CurrentTime); } /**************************************************************************** ****************************************************************************/ void RunWindowCommand(const MenuAction *action) { switch(action->type) { case MA_STICK: if(client->state.status & STAT_STICKY) { SetClientSticky(client, 0); } else { SetClientSticky(client, 1); } break; case MA_MAXIMIZE: MaximizeClient(client); break; case MA_MINIMIZE: MinimizeClient(client); break; case MA_RESTORE: RestoreClient(client, 1); break; case MA_CLOSE: DeleteClient(client); break; case MA_SENDTO: case MA_DESKTOP: SetClientDesktop(client, action->data.i); break; case MA_SHADE: if(client->state.status & STAT_SHADED) { UnshadeClient(client); } else { ShadeClient(client); } break; case MA_MOVE: MoveClientKeyboard(client); break; case MA_RESIZE: ResizeClientKeyboard(client); break; case MA_KILL: KillClient(client); break; case MA_LAYER: SetClientLayer(client, action->data.i); break; default: Debug("unknown window command: %d", action->type); break; } }