Change to the linux kernel coding style
[wmaker-crm.git] / wmlib / menu.c
1 /* menu.c - menu interface functions
2  *
3  * WMlib - WindowMaker application programming interface
4  *
5  * Copyright (C) 1997-2003 Alfredo K. Kojima
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Library General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Library General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Library General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <X11/Xlib.h>
26 #include <X11/Xutil.h>
27
28 #include "WMaker.h"
29 #include "app.h"
30 #include "menu.h"
31
32 WMMenu *WMMenuCreate(WMAppContext * app, char *title)
33 {
34         wmMenu *menu;
35
36         if (strlen(title) > 255)
37                 return NULL;
38
39         menu = malloc(sizeof(wmMenu));
40         if (!menu)
41                 return NULL;
42
43         menu->appcontext = app;
44         menu->parent = NULL;
45         menu->title = title;
46         menu->entries = NULL;
47         menu->first = NULL;
48
49         menu->realized = False;
50         menu->code = app->last_menu_tag++;
51
52         menu->entryline = malloc(strlen(title) + 32);
53         menu->entryline2 = malloc(32);
54         if (!menu->entryline || !menu->entryline2) {
55                 if (menu->entryline)
56                         free(menu->entryline);
57                 free(menu);
58                 return NULL;
59         }
60         sprintf(menu->entryline, "%i %i %s", wmBeginMenu, menu->code, title);
61         sprintf(menu->entryline2, "%i %i", wmEndMenu, menu->code);
62         return menu;
63 }
64
65 int
66 WMMenuAddItem(WMMenu * menu, char *text, WMMenuAction action,
67               void *clientData, WMFreeFunction freedata, char *rtext)
68 {
69         wmMenuEntry *entry;
70
71         /* max size of right side text */
72         if (rtext && strlen(rtext) > 4)
73                 return -1;
74
75         /* max size of menu text */
76         if (strlen(text) > 255)
77                 return -1;
78
79         entry = malloc(sizeof(wmMenuEntry));
80         if (!entry)
81                 return -1;
82
83         entry->entryline = malloc(strlen(text) + 100);
84         if (!entry->entryline) {
85                 free(menu);
86                 return -1;
87         }
88
89         if (menu->entries)
90                 entry->order = menu->entries->order + 1;
91         else {
92                 entry->order = 0;
93                 menu->first = entry;
94         }
95         entry->next = NULL;
96         entry->prev = menu->entries;
97         if (menu->entries)
98                 menu->entries->next = entry;
99         menu->entries = entry;
100
101         entry->menu = menu;
102         entry->text = text;
103         entry->shortcut = rtext;
104         entry->callback = action;
105         entry->clientData = clientData;
106         entry->free = freedata;
107         entry->tag = menu->appcontext->last_menu_tag++;
108         entry->cascade = NULL;
109         entry->enabled = True;
110
111         if (!rtext)
112                 sprintf(entry->entryline, "%i %i %i %i %s", wmNormalItem, menu->code, entry->tag, True, text);
113         else
114                 sprintf(entry->entryline, "%i %i %i %i %s %s", wmDoubleItem,
115                         menu->code, entry->tag, True, rtext, text);
116         return entry->tag;
117 }
118
119 int WMMenuAddSubmenu(WMMenu * menu, char *text, WMMenu * submenu)
120 {
121         wmMenuEntry *entry;
122
123         /* max size of menu text */
124         if (strlen(text) > 255)
125                 return -1;
126
127         entry = malloc(sizeof(wmMenuEntry));
128         if (!entry)
129                 return -1;
130
131         entry->entryline = malloc(strlen(text) + 100);
132         if (!entry->entryline) {
133                 free(menu);
134                 return -1;
135         }
136
137         if (menu->entries)
138                 entry->order = menu->entries->order + 1;
139         else {
140                 entry->order = 0;
141                 menu->first = entry;
142         }
143         entry->next = NULL;
144         entry->prev = menu->entries;
145         if (menu->entries)
146                 menu->entries->next = entry;
147         menu->entries = entry;
148         entry->menu = menu;
149         entry->text = text;
150         entry->shortcut = NULL;
151         entry->callback = NULL;
152         entry->clientData = NULL;
153         entry->tag = menu->appcontext->last_menu_tag++;
154         entry->cascade = submenu;
155         entry->enabled = True;
156
157         sprintf(entry->entryline, "%i %i %i %i %i %s", wmSubmenuItem,
158                 menu->code, entry->tag, True, submenu->code, text);
159         return entry->tag;
160 }
161
162 static int countItems(WMMenu * menu)
163 {
164         wmMenuEntry *entry = menu->first;
165         int c;
166
167         c = 1;
168         while (entry) {
169                 c++;
170                 if (entry->cascade) {
171                         c += countItems(entry->cascade);
172                 }
173                 entry = entry->next;
174         }
175         c++;
176         return c;
177 }
178
179 static void addItems(char **slist, int *index, WMMenu * menu)
180 {
181         wmMenuEntry *entry = menu->first;
182
183         slist[(*index)++] = menu->entryline;
184         while (entry) {
185                 slist[(*index)++] = entry->entryline;
186                 if (entry->cascade) {
187                         addItems(slist, index, entry->cascade);
188                 }
189                 entry = entry->next;
190         }
191         slist[(*index)++] = menu->entryline2;
192 }
193
194 static Atom getatom(Display * dpy)
195 {
196         static Atom atom = 0;
197
198         if (atom == 0) {
199                 atom = XInternAtom(dpy, WMMENU_PROPNAME, False);
200         }
201         return atom;
202 }
203
204 int WMRealizeMenus(WMAppContext * app)
205 {
206         int i, count;
207         char **slist;
208         XTextProperty text_prop;
209
210         if (!app->main_menu)
211                 return False;
212
213         /* first count how many menu items there are */
214         count = countItems(app->main_menu);
215         if (count == 0)
216                 return True;
217
218         count++;
219         slist = malloc(count * sizeof(char *));
220         if (!slist) {
221                 return False;
222         }
223
224         slist[0] = "WMMenu 0";
225         i = 1;
226         addItems(slist, &i, app->main_menu);
227
228         if (!XStringListToTextProperty(slist, i, &text_prop)) {
229                 free(slist);
230                 return False;
231         }
232         free(slist);
233         XSetTextProperty(app->dpy, app->main_window, &text_prop, getatom(app->dpy));
234
235         XFree(text_prop.value);
236
237         return True;
238 }