1 /*
2  * Copyright (C) 2000-2019 the xine project
3  *
4  * This file is part of xine, a unix video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <X11/Xlib.h>
26 #include <X11/Xutil.h>
27 #include <stdio.h>
28 
29 #include "_xitk.h"
30 
31 static void _combo_rollunroll(xitk_widget_t *w, void *data, int state);
32 
33 /*
34  *
35  */
enability(xitk_widget_t * w)36 static void enability(xitk_widget_t *w) {
37 
38   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
39 	   (w->type & WIDGET_GROUP_WIDGET))) {
40     combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
41 
42     if(w->enable == WIDGET_ENABLE) {
43       xitk_enable_widget(private_data->label_widget);
44       xitk_enable_widget(private_data->button_widget);
45     }
46     else {
47 
48       if(private_data->visible) {
49 	xitk_checkbox_set_state(private_data->button_widget, 0);
50 	_combo_rollunroll(private_data->button_widget, (void *)w, 0);
51       }
52 
53 
54       xitk_disable_widget(private_data->label_widget);
55       xitk_disable_widget(private_data->button_widget);
56     }
57 
58   }
59 }
60 
notify_destroy(xitk_widget_t * w)61 static void notify_destroy(xitk_widget_t *w) {
62 
63   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
64 	   (w->type & WIDGET_GROUP_WIDGET))) {
65     combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
66 
67     if(private_data->visible)
68       _combo_rollunroll(private_data->button_widget, (void *)w, 0);
69 
70     xitk_destroy_widgets(private_data->widget_list);
71 
72     xitk_unregister_event_handler(&private_data->widget_key);
73     xitk_window_destroy_window(private_data->imlibdata, private_data->xwin);
74 
75     XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
76     XFreeGC(private_data->imlibdata->x.disp, private_data->widget_list->gc);
77     XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
78 
79     xitk_widget_list_defferred_destroy (private_data->widget_list);
80 
81     XITK_FREE(private_data->skin_element_name);
82     free(private_data);
83   }
84 }
85 
86 /*
87  *
88  */
paint(xitk_widget_t * w)89 static void paint(xitk_widget_t *w) {
90 
91   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
92 	   (w->type & WIDGET_GROUP_WIDGET))) {
93     combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
94 
95     if(private_data->visible == 1 && (w->visible < 1)) {
96       xitk_checkbox_set_state(private_data->button_widget, 0);
97       _combo_rollunroll(private_data->button_widget, (void *)w, 0);
98     }
99     if(w->visible == 1) {
100       int bx, lw;
101 
102       lw = xitk_get_widget_width(private_data->label_widget);
103       xitk_set_widget_pos(private_data->label_widget, w->x, w->y);
104       bx = w->x + lw;
105       xitk_set_widget_pos(private_data->button_widget, bx, w->y);
106 
107       xitk_show_widget(private_data->label_widget);
108       xitk_show_widget(private_data->button_widget);
109     }
110     else {
111       xitk_hide_widget(private_data->label_widget);
112       xitk_hide_widget(private_data->button_widget);
113     }
114   }
115 }
116 
117 /*
118  *
119  */
xitk_combo_callback_exec(xitk_widget_t * w)120 void xitk_combo_callback_exec(xitk_widget_t *w) {
121 
122   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
123 	   (w->type & WIDGET_GROUP_WIDGET))) {
124     combo_private_data_t *private_data = (combo_private_data_t *)w->private_data;
125 
126     if(private_data->callback)
127       private_data->callback(private_data->combo_widget,
128 			     private_data->userdata, private_data->selected);
129 
130   }
131 }
132 
133 /*
134  * Called on select action.
135  */
combo_select(xitk_widget_t * w,void * data,int selected)136 static void combo_select(xitk_widget_t *w, void *data, int selected) {
137 
138   if(w && ((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_BROWSER)) {
139     xitk_widget_t        *c = (xitk_widget_t *) ((browser_private_data_t *)w->private_data)->userdata;
140     combo_private_data_t *private_data = (combo_private_data_t *)c->private_data;
141 
142     private_data->selected = selected;
143 
144     xitk_label_change_label(private_data->label_widget, private_data->entries[selected]);
145 
146     XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
147     XUnmapWindow(private_data->imlibdata->x.disp, (xitk_window_get_window(private_data->xwin)));
148     XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
149 
150     private_data->visible = 0;
151 
152     xitk_browser_release_all_buttons(private_data->browser_widget);
153     xitk_browser_update_list(private_data->browser_widget,
154 			     (const char* const*)private_data->entries, NULL,
155 			     private_data->num_entries, 0);
156 
157     xitk_checkbox_set_state(private_data->button_widget, 0);
158 
159     if(private_data->callback)
160       private_data->callback(private_data->combo_widget, private_data->userdata, selected);
161 
162   }
163 }
164 
165 /*
166  * Handle Xevents here.
167  */
_combo_handle_event(XEvent * event,void * data)168 static void _combo_handle_event(XEvent *event, void *data) {
169   combo_private_data_t *private_data = (combo_private_data_t *)data;
170 
171   switch(event->type) {
172 
173   case ButtonRelease:
174     /*
175      * If we try to move the combo window,
176      * move it back to right position (under label*
177      */
178     if(private_data && private_data->visible) {
179       int  x, y;
180       xitk_window_get_window_position(private_data->combo_widget->imlibdata,
181 				      private_data->xwin, &x, &y, NULL, NULL);
182       if((x != private_data->win_x) || (y != private_data->win_y))
183 	xitk_combo_update_pos(private_data->combo_widget);
184     }
185     break;
186   }
187 }
188 
189 /*
190  *
191  */
notify_change_skin(xitk_widget_t * w,xitk_skin_config_t * skonfig)192 static void notify_change_skin(xitk_widget_t *w, xitk_skin_config_t *skonfig) {
193 
194   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
195 	   (w->type & WIDGET_GROUP_WIDGET))) {
196     combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
197 
198     if(private_data->skin_element_name) {
199       int x, y;
200 
201       xitk_skin_lock(skonfig);
202 
203       w->visible = (xitk_skin_get_visibility(skonfig, private_data->skin_element_name)) ? 1 : -1;
204       w->enable  = xitk_skin_get_enability(skonfig, private_data->skin_element_name);
205 
206       xitk_set_widget_pos(w, w->x, w->y);
207       xitk_get_widget_pos(private_data->label_widget, &x, &y);
208 
209       w->x = x;
210       w->y = y;
211 
212       x += xitk_get_widget_width(private_data->label_widget);
213 
214       (void) xitk_set_widget_pos(private_data->button_widget, x, y);
215 
216       xitk_skin_unlock(skonfig);
217     }
218   }
219 }
220 
tips_timeout(xitk_widget_t * w,unsigned long timeout)221 static void tips_timeout(xitk_widget_t *w, unsigned long timeout) {
222   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
223 	   (w->type & WIDGET_GROUP_WIDGET))) {
224     combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
225 
226     private_data->combo_widget->tips_timeout = timeout;
227     private_data->label_widget->tips_timeout = timeout;
228     private_data->button_widget->tips_timeout = timeout;
229     private_data->browser_widget->tips_timeout = timeout;
230   }
231 }
232 
notify_event(xitk_widget_t * w,widget_event_t * event,widget_event_result_t * result)233 static int notify_event(xitk_widget_t *w, widget_event_t *event, widget_event_result_t *result) {
234   int retval = 0;
235 
236   switch(event->type) {
237   case WIDGET_EVENT_PAINT:
238     paint(w);
239     break;
240   case WIDGET_EVENT_CHANGE_SKIN:
241     notify_change_skin(w, event->skonfig);
242     break;
243   case WIDGET_EVENT_DESTROY:
244     notify_destroy(w);
245     break;
246   case WIDGET_EVENT_ENABLE:
247     enability(w);
248     break;
249   case WIDGET_EVENT_TIPS_TIMEOUT:
250     tips_timeout(w, event->tips_timeout);
251     break;
252   }
253 
254   return retval;
255 }
256 
257 /*
258  *
259  */
_combo_rollunroll(xitk_widget_t * w,void * data,int state)260 static void _combo_rollunroll(xitk_widget_t *w, void *data, int state) {
261   xitk_widget_t        *combo = (xitk_widget_t *)data;
262   combo_private_data_t *private_data = (combo_private_data_t *)combo->private_data;
263 
264   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
265 	   ((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_CHECKBOX))) {
266 
267     if(state && private_data->visible == 0) {
268       private_data->visible = 1;
269       xitk_combo_update_pos(combo);
270     }
271     else {
272       private_data->visible = 0;
273 
274       XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
275       XUnmapWindow(private_data->imlibdata->x.disp, (xitk_window_get_window(private_data->xwin)));
276       XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
277     }
278   }
279 }
280 
281 /*
282  *
283  */
_combo_rollunroll_from_lbl(xitk_widget_t * w,void * data)284 static void _combo_rollunroll_from_lbl(xitk_widget_t *w, void *data) {
285   xitk_widget_t        *combo = (xitk_widget_t *)data;
286   combo_private_data_t *private_data = (combo_private_data_t *)combo->private_data;
287 
288   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
289 	   ((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_LABEL))) {
290     int state;
291 
292     state = !xitk_checkbox_get_state(private_data->button_widget);
293 
294     xitk_checkbox_set_state(private_data->button_widget, state);
295 
296     if(state && private_data->visible == 0) {
297       w->wl->widget_focused = private_data->button_widget;
298       private_data->visible = 1;
299       xitk_combo_update_pos(combo);
300     }
301     else {
302       private_data->visible = 0;
303 
304       XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
305       XUnmapWindow(private_data->imlibdata->x.disp, (xitk_window_get_window(private_data->xwin)));
306       XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
307     }
308 
309   }
310 }
311 
312 /*
313  * ************************* END OF PRIVATES *******************************
314  */
315 
xitk_combo_is_same_parent(xitk_widget_t * w1,xitk_widget_t * w2)316 int xitk_combo_is_same_parent(xitk_widget_t *w1, xitk_widget_t *w2) {
317 
318   if((w1 && w2) && ((w1->type & WIDGET_GROUP_COMBO) && (w1->type & WIDGET_GROUP_COMBO))) {
319 
320     if(w1 == w2)
321       return 1;
322 
323     if(w1->wl == w2->wl) {
324       xitk_widget_list_t  *wl = w1->wl;
325       xitk_widget_t       *w, *wt;
326 
327       w = (xitk_widget_t *)wl->list.head.next;
328       while (w->node.next && ((w != w1) && (w != w2))) {
329         w = (xitk_widget_t *)w->node.next;
330       }
331 
332       if (w->node.next) {
333 
334 	wt = (w == w1) ? w2 : w1;
335 
336 	if((w->type & WIDGET_GROUP_COMBO) &&
337 	   ((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_LABEL)) {
338           w = (xitk_widget_t *)w->node.next;
339           if (w->node.next)
340             w = (xitk_widget_t *)w->node.next;
341 	}
342 	else if((w->type & WIDGET_GROUP_COMBO) &&
343 		((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_CHECKBOX)) {
344           w = (xitk_widget_t *)w->node.next;
345 	}
346 
347         if (w->node.next && ((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
348 	   (w->type & WIDGET_GROUP_WIDGET)) {
349 	  combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
350 
351 	  if((wt == private_data->label_widget) || (wt == private_data->button_widget))
352 	    return 1;
353 
354 	}
355 
356       }
357     }
358   }
359   return 0;
360 }
361 
362 /*
363  *
364  */
xitk_combo_rollunroll(xitk_widget_t * w)365 void xitk_combo_rollunroll(xitk_widget_t *w) {
366 
367   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO))) {
368 
369     if((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_CHECKBOX) {
370       int state = !xitk_checkbox_get_state(w);
371       xitk_checkbox_callback_exec(w);
372       xitk_checkbox_set_state(w, state);
373     }
374   }
375   else if(w->type & WIDGET_GROUP_WIDGET) {
376     combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
377     int state = !xitk_checkbox_get_state(private_data->button_widget);
378       xitk_checkbox_callback_exec(private_data->button_widget);
379       xitk_checkbox_set_state(private_data->button_widget, state);
380   }
381 }
382 
383   /*
384    *
385    */
xitk_combo_set_select(xitk_widget_t * w,int select)386 void xitk_combo_set_select(xitk_widget_t *w, int select) {
387 
388   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
389 	   (w->type & WIDGET_GROUP_WIDGET))) {
390     combo_private_data_t *private_data = (combo_private_data_t *)w->private_data;
391 
392     if(private_data->entries && private_data->entries[select]) {
393       private_data->selected = select;
394       xitk_label_change_label(private_data->label_widget, private_data->entries[select]);
395     }
396 
397   }
398 }
399 
400 /*
401  *
402  */
xitk_combo_update_pos(xitk_widget_t * w)403 void xitk_combo_update_pos(xitk_widget_t *w) {
404 
405   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
406 	   (w->type & WIDGET_GROUP_WIDGET))) {
407     combo_private_data_t  *private_data = (combo_private_data_t *)w->private_data;
408     int                    xx = 0, yy = 0;
409     window_info_t          wi;
410     XSizeHints             hint;
411 
412     if(private_data->visible) {
413       if((xitk_get_window_info(*(private_data->parent_wkey), &wi))) {
414 	private_data->win_x = wi.x;
415 	private_data->win_y = wi.y;
416 	WINDOW_INFO_ZERO(&wi);
417       }
418 
419       xitk_get_widget_pos(private_data->label_widget, &xx, &yy);
420 
421       yy += xitk_get_widget_height(private_data->label_widget);
422       private_data->win_x += xx;
423       private_data->win_y += yy;
424 
425       hint.x = private_data->win_x;
426       hint.y = private_data->win_y;
427       hint.flags = PPosition;
428 
429       XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
430       XSetWMNormalHints (private_data->imlibdata->x.disp,
431 			 xitk_window_get_window(private_data->xwin),
432 			 &hint);
433       XMoveWindow(private_data->imlibdata->x.disp,
434 		  (xitk_window_get_window(private_data->xwin)),
435 		  private_data->win_x, private_data->win_y);
436       XMapRaised(private_data->imlibdata->x.disp, (xitk_window_get_window(private_data->xwin)));
437       XSync(private_data->imlibdata->x.disp, False);
438       XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
439 
440       while(!xitk_is_window_visible(private_data->imlibdata->x.disp,
441 				    (xitk_window_get_window(private_data->xwin))))
442 	xitk_usec_sleep(5000);
443 
444       XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
445       XSetInputFocus(private_data->imlibdata->x.disp,
446 		     (xitk_window_get_window(private_data->xwin)), RevertToParent, CurrentTime);
447       XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
448 
449       /* No widget focused, give focus to the first one */
450       if(private_data->widget_list->widget_focused == NULL)
451 	xitk_set_focus_to_next_widget(private_data->widget_list, 0);
452 
453     }
454   }
455 }
456 
457 /*
458  *
459  */
xitk_combo_get_current_selected(xitk_widget_t * w)460 int xitk_combo_get_current_selected(xitk_widget_t *w) {
461 
462   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
463 	   (w->type & WIDGET_GROUP_WIDGET))) {
464     combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
465 
466     return private_data->selected;
467   }
468 
469   return -1;
470 }
471 
472 /*
473  *
474  */
xitk_combo_get_current_entry_selected(xitk_widget_t * w)475 const char *xitk_combo_get_current_entry_selected(xitk_widget_t *w) {
476 
477   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
478 	   (w->type & WIDGET_GROUP_WIDGET))) {
479     combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
480 
481     if(private_data->entries && private_data->selected >= 0)
482       return(private_data->entries[private_data->selected]);
483   }
484 
485   return NULL;
486 }
487 
488 /*
489  *
490  */
xitk_combo_update_list(xitk_widget_t * w,const char * const * const list,int len)491 void xitk_combo_update_list(xitk_widget_t *w, const char *const *const list, int len) {
492 
493   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
494 	   (w->type & WIDGET_GROUP_WIDGET))) {
495     combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
496 
497     private_data->entries     = list;
498     private_data->num_entries = len;
499     private_data->selected    = -1;
500 
501     xitk_browser_update_list(private_data->browser_widget,
502 			     (const char* const*)private_data->entries, NULL,
503 			     private_data->num_entries, 0);
504   }
505 }
506 
507 /*
508  *
509  */
xitk_combo_get_label_widget(xitk_widget_t * w)510 xitk_widget_t *xitk_combo_get_label_widget(xitk_widget_t *w) {
511 
512   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
513 	   (w->type & WIDGET_GROUP_WIDGET))) {
514     combo_private_data_t *private_data = (combo_private_data_t *) w->private_data;
515 
516     return private_data->label_widget;
517   }
518 
519   return NULL;
520 }
521 
522 /*
523  *
524  */
_xitk_combo_create(xitk_widget_list_t * wl,xitk_skin_config_t * skonfig,xitk_combo_widget_t * c,const char * skin_element_name,xitk_widget_t * mywidget,combo_private_data_t * private_data,int visible,int enable)525 static xitk_widget_t *_xitk_combo_create(xitk_widget_list_t *wl,
526 					 xitk_skin_config_t *skonfig,
527                                          xitk_combo_widget_t *c, const char *skin_element_name,
528 					 xitk_widget_t *mywidget,
529 					 combo_private_data_t *private_data,
530 					 int visible, int enable) {
531   Atom                        XA_WIN_LAYER;
532   long                        data[1];
533   const char                **entries = c->entries;
534   unsigned int                itemw, itemh = 20;
535   unsigned int                slidw = 12;
536   xitk_browser_widget_t       browser;
537   XClassHint                  xclasshint;
538   Status                      status;
539 
540   XITK_WIDGET_INIT(&browser, c->imlibdata);
541 
542   itemw = xitk_get_widget_width(private_data->label_widget);
543   itemw += xitk_get_widget_width(private_data->button_widget);
544   itemw -= 2; /* space for border */
545 
546   private_data->imlibdata                = c->imlibdata;
547   private_data->skin_element_name        = (skin_element_name == NULL) ? NULL : strdup(skin_element_name);
548   private_data->entries                  = c->entries;
549   private_data->combo_widget             = mywidget;
550   private_data->parent_wlist             = c->parent_wlist;
551   private_data->parent_wkey              = c->parent_wkey;
552   private_data->callback                 = c->callback;
553   private_data->userdata                 = c->userdata;
554 
555   private_data->selected = -1;
556   {
557     int i = 0;
558 
559     while(entries[i] != NULL) {
560       i++;
561     }
562 
563     private_data->num_entries = i;
564   }
565 
566   if(private_data->num_entries) {
567     xitk_label_change_label(private_data->label_widget, entries[0]);
568     private_data->selected = 0;
569   }
570 
571   private_data->xwin = xitk_window_create_simple_window(c->imlibdata, 0, 0,
572 							(itemw + 2), (itemh * 5) + slidw + 2);
573   XLOCK (c->imlibdata->x.x_lock_display, c->imlibdata->x.disp);
574 
575   {
576     XSetWindowAttributes attr;
577     attr.override_redirect = True;
578     XLOCK (c->imlibdata->x.x_lock_display, c->imlibdata->x.disp);
579     XChangeWindowAttributes (c->imlibdata->x.disp,
580 			     (xitk_window_get_window(private_data->xwin)),
581 			     CWOverrideRedirect, &attr);
582     XUNLOCK (c->imlibdata->x.x_unlock_display, c->imlibdata->x.disp);
583   }
584 
585   if(c->layer_above) {
586     XA_WIN_LAYER = XInternAtom(c->imlibdata->x.disp, "_WIN_LAYER", False);
587 
588     data[0] = 10;
589     XChangeProperty(c->imlibdata->x.disp,
590 		    (xitk_window_get_window(private_data->xwin)), XA_WIN_LAYER,
591 		    XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data,
592 		    1);
593   }
594 
595   XSetTransientForHint (c->imlibdata->x.disp,
596 			(xitk_window_get_window(private_data->xwin)), private_data->parent_wlist->win);
597 
598   /* Change default classhint to new one. */
599   if((status = XGetClassHint(c->imlibdata->x.disp,
600 		     (xitk_window_get_window(private_data->xwin)), &xclasshint)) != BadWindow) {
601     XFree(xclasshint.res_name);
602     XFree(xclasshint.res_class);
603     xclasshint.res_name  = (char *)"Xitk Combo";
604     xclasshint.res_class = (char *)"Xitk";
605     XSetClassHint(c->imlibdata->x.disp, (xitk_window_get_window(private_data->xwin)), &xclasshint);
606   }
607 
608   private_data->gc = XCreateGC(c->imlibdata->x.disp,
609 			       (xitk_window_get_window(private_data->xwin)), None, None);
610 
611   XUNLOCK (c->imlibdata->x.x_unlock_display, c->imlibdata->x.disp);
612 
613   private_data->widget_list                = xitk_widget_list_new() ;
614   xitk_dlist_init (&private_data->widget_list->list);
615   private_data->widget_list->win           = (xitk_window_get_window(private_data->xwin));
616   private_data->widget_list->gc            = private_data->gc;
617 
618   /* Browser */
619   browser.imlibdata                     = private_data->imlibdata;
620   browser.arrow_up.skin_element_name    = NULL;
621   browser.slider.skin_element_name      = NULL;
622   browser.arrow_dn.skin_element_name    = NULL;
623   browser.browser.skin_element_name     = NULL;
624   browser.browser.max_displayed_entries = 5;
625   browser.browser.num_entries           = private_data->num_entries;
626   browser.browser.entries               = (const char* const*)private_data->entries;
627   browser.callback                      = combo_select;
628   browser.dbl_click_callback            = NULL;
629   browser.parent_wlist                  = private_data->widget_list;
630   browser.userdata                      = (void*)mywidget;
631   private_data->browser_widget = xitk_noskin_browser_create (private_data->widget_list, &browser,
632     private_data->gc, 1, 1, (itemw - slidw), itemh, slidw, DEFAULT_FONT_10);
633   xitk_dlist_add_tail (&private_data->widget_list->list, &private_data->browser_widget->node);
634   xitk_enable_and_show_widget(private_data->browser_widget);
635   private_data->browser_widget->type |= WIDGET_GROUP | WIDGET_GROUP_COMBO;
636 
637   xitk_browser_update_list(private_data->browser_widget,
638 			   (const char* const*)private_data->entries, NULL,
639 			   private_data->num_entries, 0);
640 
641   private_data->widget_key =
642     xitk_register_event_handler("xitk combo",
643 				(xitk_window_get_window(private_data->xwin)),
644 				_combo_handle_event,
645 				NULL,
646 				NULL,
647 				private_data->widget_list,
648 				(void *) private_data);
649 
650   private_data->visible  = 0;
651 
652   mywidget->private_data = private_data;
653   mywidget->wl           = wl;
654   mywidget->enable       = enable;
655   mywidget->running      = 1;
656   mywidget->visible      = visible;
657   mywidget->have_focus   = FOCUS_LOST;
658 
659   mywidget->imlibdata    = private_data->imlibdata;
660   //  mywidget->x = mywidget->y = mywidget->width = mywidget->height = 0;
661   mywidget->type         = WIDGET_GROUP | WIDGET_GROUP_WIDGET | WIDGET_GROUP_COMBO;
662   mywidget->event        = notify_event;
663   mywidget->tips_timeout = 0;
664   mywidget->tips_string  = NULL;
665 
666   return mywidget;
667 }
668 
669 /*
670  *
671  */
xitk_combo_create(xitk_widget_list_t * wl,xitk_skin_config_t * skonfig,xitk_combo_widget_t * c,xitk_widget_t ** lw,xitk_widget_t ** bw)672 xitk_widget_t *xitk_combo_create(xitk_widget_list_t *wl,
673 				 xitk_skin_config_t *skonfig, xitk_combo_widget_t *c,
674 				 xitk_widget_t **lw, xitk_widget_t **bw) {
675   xitk_widget_t              *mywidget;
676   combo_private_data_t       *private_data;
677   xitk_checkbox_widget_t      cb;
678   xitk_label_widget_t         lbl;
679 
680   XITK_CHECK_CONSTITENCY(c);
681 
682   mywidget = (xitk_widget_t *) xitk_xmalloc (sizeof(xitk_widget_t));
683 
684   XITK_WIDGET_INIT(&cb, c->imlibdata);
685   XITK_WIDGET_INIT(&lbl, c->imlibdata);
686 
687   private_data = (combo_private_data_t *) xitk_xmalloc (sizeof(combo_private_data_t));
688 
689   /* Create label and button (skinable) */
690   lbl.label             = "";
691   lbl.skin_element_name = c->skin_element_name;
692   lbl.window            = c->parent_wlist->win;
693   lbl.gc                = c->parent_wlist->gc;
694   lbl.callback          = _combo_rollunroll_from_lbl;
695   lbl.userdata          = (void *)mywidget;
696   private_data->label_widget = xitk_label_create (c->parent_wlist, skonfig, &lbl);
697   xitk_dlist_add_tail (&c->parent_wlist->list, &private_data->label_widget->node);
698   private_data->label_widget->type |= WIDGET_GROUP | WIDGET_GROUP_COMBO;
699 
700   cb.skin_element_name = c->skin_element_name;
701   cb.callback          = _combo_rollunroll;
702   cb.userdata          = (void *)mywidget;
703   private_data->button_widget = xitk_checkbox_create (c->parent_wlist, skonfig, &cb);
704   xitk_dlist_add_tail (&c->parent_wlist->list, &private_data->button_widget->node);
705   private_data->button_widget->type |= WIDGET_GROUP | WIDGET_GROUP_COMBO;
706 
707   if(lw)
708     *lw = private_data->label_widget;
709   if(bw)
710     *bw = private_data->button_widget;
711 
712   {
713     int x, y;
714 
715     xitk_get_widget_pos(private_data->label_widget, &x, &y);
716 
717     mywidget->x = x;
718     mywidget->y = y;
719 
720     x += xitk_get_widget_width(private_data->label_widget);
721 
722     (void) xitk_set_widget_pos(private_data->button_widget, x, y);
723   }
724   return _xitk_combo_create(wl, skonfig, c, c->skin_element_name, mywidget, private_data,
725 			    (xitk_skin_get_visibility(skonfig, c->skin_element_name)) ? 1 : -1,
726 			    xitk_skin_get_enability(skonfig, c->skin_element_name));
727 }
728 
729 /*
730  *  ******************************************************************************
731  */
xitk_noskin_combo_create(xitk_widget_list_t * wl,xitk_combo_widget_t * c,int x,int y,int width,xitk_widget_t ** lw,xitk_widget_t ** bw)732 xitk_widget_t *xitk_noskin_combo_create(xitk_widget_list_t *wl,
733 					xitk_combo_widget_t *c,
734 					int x, int y, int width,
735 					xitk_widget_t **lw, xitk_widget_t **bw) {
736   xitk_widget_t              *mywidget;
737   combo_private_data_t       *private_data;
738   xitk_checkbox_widget_t      cb;
739   xitk_label_widget_t         lbl;
740 
741   XITK_CHECK_CONSTITENCY(c);
742 
743   mywidget = (xitk_widget_t *) xitk_xmalloc (sizeof(xitk_widget_t));
744 
745   XITK_WIDGET_INIT(&cb, c->imlibdata);
746   XITK_WIDGET_INIT(&lbl, c->imlibdata);
747 
748   private_data = (combo_private_data_t *) xitk_xmalloc (sizeof(combo_private_data_t));
749 
750   /* Create label and button (skinable) */
751   {
752     xitk_font_t    *fs;
753     int             height;
754 
755     fs = xitk_font_load_font(c->imlibdata->x.disp, DEFAULT_FONT_10);
756     xitk_font_set_font(fs, c->parent_wlist->gc);
757     height = xitk_font_get_string_height(fs, " ") + 4;
758     xitk_font_unload_font(fs);
759 
760 
761     lbl.window            = c->parent_wlist->win;
762     lbl.gc                = c->parent_wlist->gc;
763     lbl.skin_element_name = NULL;
764     lbl.label             = "";
765     lbl.callback          = _combo_rollunroll_from_lbl;
766     lbl.userdata          = (void *)mywidget;
767     private_data->label_widget = xitk_noskin_label_create (c->parent_wlist, &lbl,
768       x, y, (width - height), height, DEFAULT_FONT_10);
769     xitk_dlist_add_tail (&c->parent_wlist->list, &private_data->label_widget->node);
770     private_data->label_widget->type |= WIDGET_GROUP | WIDGET_GROUP_COMBO;
771 
772     cb.skin_element_name = NULL;
773     cb.callback          = _combo_rollunroll;
774     cb.userdata          = (void *)mywidget;
775 
776     private_data->button_widget = xitk_noskin_checkbox_create (c->parent_wlist, &cb,
777       x + (width - height), y, height, height);
778     xitk_dlist_add_tail (&c->parent_wlist->list, &private_data->button_widget->node);
779     private_data->button_widget->type |= WIDGET_GROUP | WIDGET_GROUP_COMBO;
780 
781     if(lw)
782       *lw = private_data->label_widget;
783     if(bw)
784       *bw = private_data->button_widget;
785 
786     mywidget->x = x;
787     mywidget->y = y;
788     mywidget->width = width;
789     mywidget->height = height;
790 
791     {
792       xitk_image_t *wimage = xitk_get_widget_foreground_skin(private_data->label_widget);
793 
794       if(wimage)
795 	draw_rectangular_inner_box(c->imlibdata, wimage->image, 0, 0, wimage->width - 1, wimage->height - 1);
796 
797       wimage = xitk_get_widget_foreground_skin(private_data->button_widget);
798 
799       if(wimage) {
800 	draw_bevel_three_state(c->imlibdata, wimage);
801 	draw_arrow_down(c->imlibdata, wimage);
802       }
803 
804     }
805 
806   }
807 
808   return _xitk_combo_create(wl, NULL, c, NULL, mywidget, private_data, 0, 0);
809 }
810