/**
* @file root.c
* @author Joe Wingbermuehle
* @date 2004-2006
*
* @brief Functions to handle root menus.
*
*/
#include "jwm.h"
#include "root.h"
#include "menu.h"
#include "client.h"
#include "main.h"
#include "error.h"
#include "confirm.h"
#include "desktop.h"
#include "misc.h"
#include "winmenu.h"
#include "command.h"
/** Number of root menus to support. */
#define ROOT_MENU_COUNT 10
static Menu *rootMenu[ROOT_MENU_COUNT];
static int showExitConfirmation = 1;
static void ExitHandler(ClientNode *np);
static void PatchRootMenu(Menu *menu);
static void UnpatchRootMenu(Menu *menu);
static void RunRootCommand(const MenuAction *action);
/** Initialize root menu data. */
void InitializeRootMenu() {
int x;
for(x = 0; x < ROOT_MENU_COUNT; x++) {
rootMenu[x] = NULL;
}
}
/** Startup root menus. */
void StartupRootMenu() {
int x, y;
int found;
for(x = 0; x < ROOT_MENU_COUNT; x++) {
if(rootMenu[x]) {
found = 0;
for(y = 0; y < x; y++) {
if(rootMenu[y] == rootMenu[x]) {
found = 1;
break;
}
}
if(!found) {
InitializeMenu(rootMenu[x]);
}
}
}
}
/** Shutdown root menus. */
void ShutdownRootMenu() {
}
/** Destroy root menu data. */
void DestroyRootMenu() {
int x, y;
for(x = 0; x < ROOT_MENU_COUNT; x++) {
if(rootMenu[x]) {
DestroyMenu(rootMenu[x]);
for(y = x + 1; y < ROOT_MENU_COUNT; y++) {
if(rootMenu[x] == rootMenu[y]) {
rootMenu[y] = NULL;
}
}
rootMenu[x] = NULL;
}
}
}
/** Set a root menu. */
void SetRootMenu(const char *indexes, Menu *m) {
int x, y;
int index;
int found;
/* Loop over each index to consider. */
for(x = 0; indexes[x]; x++) {
/* Get the index and make sure it's in range. */
index = indexes[x] - '0';
if(index < 0 || index >= ROOT_MENU_COUNT) {
Warning("invalid root menu specified: \"%c\"", indexes[x]);
continue;
}
if(rootMenu[index] && rootMenu[index] != m) {
/* See if replacing this value will cause an orphan. */
found = 0;
for(y = 0; y < ROOT_MENU_COUNT; y++) {
if(x != y && rootMenu[y] == rootMenu[x]) {
found = 1;
break;
}
}
/* If we have an orphan, destroy it. */
if(!found) {
DestroyMenu(rootMenu[index]);
}
}
rootMenu[index] = m;
}
}
/** Set whether a dialog should be shown before exiting. */
void SetShowExitConfirmation(int v) {
showExitConfirmation = v;
}
/** Determine if the specified root menu is defined. */
int IsRootMenuDefined(int index) {
if(index >= 0 && index < ROOT_MENU_COUNT && rootMenu[index]) {
return 1;
} else {
return 0;
}
}
/** Determine the size of a root menu. */
void GetRootMenuSize(int index, int *width, int *height) {
if(!rootMenu[index]) {
*width = 0;
*height = 0;
return;
}
PatchRootMenu(rootMenu[index]);
*width = rootMenu[index]->width;
*height = rootMenu[index]->height;
UnpatchRootMenu(rootMenu[index]);
}
/** Show a root menu. */
int ShowRootMenu(int index, int x, int y) {
if(!rootMenu[index]) {
return 0;
}
PatchRootMenu(rootMenu[index]);
ShowMenu(rootMenu[index], RunRootCommand, x, y);
UnpatchRootMenu(rootMenu[index]);
return 1;
}
/** Prepare a root menu to be shown. */
void PatchRootMenu(Menu *menu) {
MenuItem *item;
for(item = menu->items; item; item = item->next) {
if(item->submenu) {
PatchRootMenu(item->submenu);
}
if(item->action.type == MA_DESKTOP) {
item->submenu = CreateDesktopMenu(1 << currentDesktop);
InitializeMenu(item->submenu);
}
}
}
/** Remove temporary items from a root menu. */
void UnpatchRootMenu(Menu *menu) {
MenuItem *item;
for(item = menu->items; item; item = item->next) {
if(item->action.type == MA_DESKTOP) {
DestroyMenu(item->submenu);
item->submenu = NULL;
} else if(item->submenu) {
UnpatchRootMenu(item->submenu);
}
}
}
/** Exit callback for the exit menu item. */
void ExitHandler(ClientNode *np) {
shouldExit = 1;
}
/** Restart callback for the restart menu item. */
void Restart() {
shouldRestart = 1;
shouldExit = 1;
}
/** Exit with optional confirmation. */
void Exit() {
if(showExitConfirmation) {
ShowConfirmDialog(NULL, ExitHandler,
"Exit JWM",
"Are you sure?",
NULL);
} else {
ExitHandler(NULL);
}
}
/** Root menu callback. */
void RunRootCommand(const MenuAction *action) {
switch(action->type) {
case MA_EXECUTE:
RunCommand(action->data.str);
break;
case MA_RESTART:
Restart();
break;
case MA_EXIT:
if(exitCommand) {
Release(exitCommand);
}
exitCommand = CopyString(action->data.str);
Exit();
break;
case MA_DESKTOP:
ChangeDesktop(action->data.i);
break;
case MA_SENDTO:
case MA_LAYER:
case MA_MAXIMIZE:
case MA_MINIMIZE:
case MA_RESTORE:
case MA_SHADE:
case MA_MOVE:
case MA_RESIZE:
case MA_KILL:
case MA_CLOSE:
ChooseWindow(action);
break;
default:
Debug("invalid RunRootCommand action: %d", action->type);
break;
}
}
syntax highlighted by Code2HTML, v. 0.9.1