Support for password authentification in adesklets_submit
[adesklets.git] / src / xmenu.c
blob5548fe84e49888c52c4cd4522acb7239be78faab
1 /*--- xmenu.c ------------------------------------------------------------------
2 Copyright (C) 2004, 2005, 2006 Sylvain Fourmanoit <syfou@users.sourceforge.net>
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to
6 deal in the Software without restriction, including without limitation the
7 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 sell copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies of the Software and its documentation and acknowledgment shall be
13 given in the documentation and software packages that this Software was
14 used.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 ------------------------------------------------------------------------------*/
23 /* Simple X Windows menu API */
25 /*----------------------------------------------------------------------------*/
26 #include "xmenu.h" /* xmenu headers */
28 #ifdef HAVE_STRING_H
29 #include <string.h> /* strlen, strcpy functions */
30 #endif
32 /*----------------------------------------------------------------------------*/
33 #define XMENU_X_BORDER 10
34 #define XMENU_Y_BORDER 5
36 /*----------------------------------------------------------------------------*/
37 /* This is logically part of command.h/command.c, but we need it here also.
39 extern char * dupstr_utf8(const char *);
41 /*----------------------------------------------------------------------------*/
42 xmenu *
43 xmenu_init(void)
45 xmenu * menu;
46 if ((menu=(xmenu*)malloc(sizeof(xmenu)))) {
47 if (!(menu->content=tree_init())) {
48 free(menu);
49 menu=NULL;
50 } else
51 menu->pos=menu->content;
53 return menu;
56 /*----------------------------------------------------------------------------*/
57 int
58 xmenu_push_item(xmenu * menu, const char * item)
60 int result=0;
61 char * str;
62 if(menu && item) {
63 TRY_CATCH(str=malloc(strlen(item)+1));
64 strcpy(str,item);
65 if (tree_push(menu->pos,str))
66 result=1;
68 return result;
71 /*----------------------------------------------------------------------------*/
72 int
73 xmenu_push_submenu(xmenu * menu, const char * item)
75 int result=0;
76 char * str;
78 if(menu && item) {
79 TRY_CATCH(str=malloc(strlen(item)));
80 strcpy(str,item);
81 if (tree_push(menu->pos,str)) {
82 menu->pos=
83 (tree*)menu->pos->children->content[menu->pos->children->pos-1];
84 result=1;
87 return result;
90 /*----------------------------------------------------------------------------*/
91 int
92 xmenu_end_submenu(xmenu * menu)
94 return (menu->pos->parent)?(menu->pos=menu->pos->parent)!=NULL:0;
97 /*----------------------------------------------------------------------------*/
98 void
99 xmenu_list_callback(tree* mytree,uint depth, uint pos, void *params) {
100 printf("String: %s\tDepth: %u\tPos: %u\n",(char*)mytree->content,depth,pos);
103 /*----------------------------------------------------------------------------*/
105 xmenu_build_image(tree *pos, int width, int height, int active)
107 int i,h,x,y,
108 result=0;
109 char * item;
110 Imlib_Image image;
111 Imlib_Font font;
112 ImlibPolygon poly;
114 if ((font=imlib_load_font("Vera/12")) &&
115 (image=imlib_create_image(width,height))) {
116 imlib_context_set_font(font);
117 imlib_context_set_image(image);
118 /* Fill image in light grey */
119 imlib_context_set_color(200, 200, 200, 255);
120 imlib_image_fill_rectangle(0,0,width,height);
121 imlib_context_set_color(0,0,0,255);
122 /* Iterate and generate text, normal or inverted */
123 for(h=XMENU_Y_BORDER,i=0;i<pos->children->pos;++i,h+=y) {
124 item=dupstr_utf8(((tree*)(pos->children->content[i]))->content);
125 if (*((char*)((tree*)pos->children->content[i])->content)!='-')
126 if (item)
127 imlib_get_text_size(item, &x, &y);
128 else
129 x=y=0;
130 else {
131 x=-1; y=XMENU_Y_BORDER;
134 if(i==active) {
135 imlib_image_fill_rectangle(0,h,width,y);
136 imlib_context_set_color(255,255,255,255);
138 if (x!=-1) {
139 if (item) imlib_text_draw(XMENU_X_BORDER,h,item);
140 } else
141 imlib_image_draw_line(0,h+y/2,width,h+y/2,0);
143 /* Potential submenu item: show it! */
144 if (((tree*)(pos->children->content[i]))->children->pos) {
145 if ((poly=imlib_polygon_new())) {
146 imlib_polygon_add_point(poly,width-XMENU_X_BORDER+3,h+y);
147 imlib_polygon_add_point(poly,width-XMENU_X_BORDER+3,h);
148 imlib_polygon_add_point(poly,width,h+y/2);
149 imlib_image_fill_polygon(poly);
150 imlib_polygon_free(poly);
152 if ((poly=imlib_polygon_new())) {
153 imlib_polygon_add_point(poly,XMENU_X_BORDER-3,h+y);
154 imlib_polygon_add_point(poly,XMENU_X_BORDER-3,h);
155 imlib_polygon_add_point(poly,0,h+y/2);
156 imlib_image_fill_polygon(poly);
157 imlib_polygon_free(poly);
160 if (i==active) imlib_context_set_color(0,0,0,255);
161 free(item);
163 imlib_free_font();
164 result=1;
166 return result;
169 /*----------------------------------------------------------------------------*/
170 /* This (too long) function just generates a menu, prints it, and manages it
171 until the user made its choice, including submenu generation and
172 parent window update. Returns a pointer to the string of what was selected,
173 or null otherwise.
175 char *
176 xmenu_fire(Display * display, int scr,
177 Window parent,
178 Imlib_Image parent_background, Imlib_Image parent_foreground,
179 int transparency,
180 xmenu * menu)
182 #ifndef X_DISPLAY_MISSING
183 char *item, * result = NULL;
184 int x, y, z, width, height, depth,
185 active_item, exit_flag;
186 int * heights;
187 tree * pos;
188 Window window;
189 Visual * visual;
190 XWindowAttributes attr;
191 XEvent ev;
192 Imlib_Updates updates;
193 Imlib_Font font;
195 if (menu) {
196 /* Set original position */
197 pos=menu->content;
199 /* Return silently if no items */
200 if(!pos->children->pos) return NULL;
202 do {
203 active_item=-1; exit_flag=0;
205 TRY_CATCH(heights=(int*)malloc(sizeof(int)*pos->children->pos));
207 /* Imlib2 context save */
208 xwindow_context_save(IMLIB_VISUAL|IMLIB_DRAWABLE|
209 IMLIB_IMAGE|IMLIB_FONT|IMLIB_DIRECTION);
210 /* Determine width and height of menu */
211 imlib_context_set_direction(IMLIB_TEXT_TO_RIGHT);
212 if ((font=imlib_load_font("Vera/12"))) {
213 /* Get screen dimentions via its root window attributes */
214 XGetWindowAttributes(display,
215 RootWindowOfScreen(ScreenOfDisplay(display,scr)),
216 &attr);
217 imlib_context_set_font(font);
218 for(width=0,height=0,z=0;
219 z<pos->children->pos;
220 heights[z++]=(height+=y),width=(x>width)?x:width) {
221 if (*((char*)((tree*)pos->children->content[z])->content)!='-') {
222 /* Real text */
223 if ((item=dupstr_utf8(((tree*)(pos->children->content[z]))->content))) {
224 imlib_get_text_size(item, &x, &y);
225 free(item);
226 } else
227 x=y=0;
228 } else {
229 /* Separator */
230 x=0; y=XMENU_Y_BORDER;
233 imlib_free_font();
235 /* Verify that there is something to write */
236 if (width && height) {
237 width+=2*XMENU_X_BORDER; height+=2*XMENU_Y_BORDER;
238 /* Get actual pointer position: to work, the pointer need
239 to be on the same screen */
240 if(XQueryPointer(display,
241 RootWindowOfScreen(ScreenOfDisplay(display,scr)),
242 &window,&window,&x,&y,&z,&z,(uint*)&z)) {
243 /* Windows coordinates computation */
244 x=((x-=width/2)<0)?0:x;
245 y=((y-=height/2)<0)?0:y;
246 x=((x+width)<=attr.width)?x:attr.width-width;
247 y=((y+height)<=attr.height)?y:attr.height-height;
248 /* Create the window */
249 if((window=
250 XCreateWindow(display,
251 RootWindowOfScreen(ScreenOfDisplay(display,scr)),
252 x, y, width, height, 0,
253 DefaultDepth(display,scr),
254 InputOutput,
255 visual=
256 imlib_get_best_visual(display,scr,&depth),
257 CWOverrideRedirect|CWBackPixel,
258 &XDefaultWindowAttributes))) {
259 /* Select events */
260 XSelectInput(display, window,
261 PointerMotionMask | ButtonPressMask |
262 ExposureMask | LeaveWindowMask);
263 /* Imlib2 settings */
264 imlib_context_set_visual(visual);
265 imlib_context_set_drawable(window);
267 /* Finally, map and manage the window */
268 XMapRaised(display,window);
269 do {
270 updates = imlib_updates_init();
271 while(XCheckWindowEvent(display,parent,
272 ExposureMask,
273 &ev) ||
274 XCheckWindowEvent(display,window,
275 PointerMotionMask | ButtonPressMask |
276 ExposureMask | LeaveWindowMask,
277 &ev)) {
278 switch(ev.type) {
279 case Expose:
280 if(ev.xexpose.window==parent) {
281 /* Refresh updates list */
282 updates = imlib_update_append_rect(updates,
283 ev.xexpose.x,
284 ev.xexpose.y,
285 ev.xexpose.width,
286 ev.xexpose.height);
287 break;
289 case MotionNotify:
290 for(z=0;
291 z<pos->children->pos &&
292 ((XMotionEvent*)&ev.xbutton)->y-XMENU_Y_BORDER>
293 heights[z];
294 ++z);
295 z=(z==pos->children->pos)?pos->children->pos-1:z;
296 z=(*((char*)((tree*)pos->children->content[z])->content)
297 !='-')?z:active_item;
298 if(z!=active_item &&
299 xmenu_build_image(pos,width,height,z)) {
300 imlib_render_image_on_drawable(0,0);
301 imlib_free_image();
302 active_item=z;
304 break;
305 case LeaveNotify:
306 active_item=-1;
307 case ButtonPress:
308 exit_flag=1;
309 break;
313 /* Perform parent window updates as needed */
314 xwindow_update_window(parent, &updates,
315 parent_background,
316 parent_foreground,
317 transparency);
318 if(updates) imlib_updates_free(updates);
320 /* Now a bit of sleep */
321 usleep(X_POLLING_PERIOD);
322 } while(!exit_flag);
324 /* Unmap and destroy the window */
325 XUnmapWindow(display,window);
326 XDestroyWindow(display,window);
327 /* !!! */
328 XSync(display, False);
330 /* Others cleaning */
331 free(heights);
336 /* Imlib2 restore original context settings */
337 xwindow_context_restore();
338 /* Do it again entirely if the user clicked on a submenu */
339 } while(active_item!=-1 &&
340 (((tree*)pos->children->content[active_item])->children->pos)?
341 pos=(tree*)pos->children->content[active_item],1:0);
343 result=(active_item!=-1)?
344 ((char*)((tree*)pos->children->content[active_item])->content):NULL;
346 return result;
347 #else /* X_MISSING_DISPLAY */
348 return NULL;
349 #endif
352 /*----------------------------------------------------------------------------*/
353 xmenu *
354 xmenu_free(xmenu * menu)
356 if ((menu->content=tree_free(menu->content))==NULL) {
357 free(menu);
358 menu=NULL;
360 return menu;
363 /*----------------------------------------------------------------------------*/
364 void *
365 xmenu_vector_free_item(void* menu)
367 return xmenu_free((xmenu*)menu);
370 /*----------------------------------------------------------------------------*/