comparison gtk4/dw.c @ 2264:5c981407b0f3

GTK4: Add experimental support for GTK4... This is in progress and doesn't compile yet. GTK4 support will likely be less full than GTK3 due to architectural decisions by the GTK team. Certain features have been removed with no replacements, such as status icon support. Additionally all of the thread safety has been removed and everything MUST run on the main thread. I will likely implement a similar solution to what I did on MacOS where threads will call into the main thread to do API calls, passing the arguments between threads. Copied from GTK3 removing all existing now dead thread safety, all deprecated code and everything supporting earlier versions of GTK3. GTK4 is not available in any mainstream distributions yet... hoping to have it at least functional by the time there are any.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Fri, 29 Jan 2021 10:57:12 +0000
parents
children 63bb97e94cd3
comparison
equal deleted inserted replaced
2263:176470d75695 2264:5c981407b0f3
1 /*
2 * Dynamic Windows:
3 * A GTK like cross-platform GUI
4 * GTK4 forwarder module for portabilty.
5 *
6 * (C) 2000-2021 Brian Smith <brian@dbsoft.org>
7 * (C) 2003-2011 Mark Hessling <mark@rexx.org>
8 */
9 #include "dwconfig.h"
10 #include "dw.h"
11 #include <glib/gi18n.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <sys/utsname.h>
15 #include <sys/socket.h>
16 #include <sys/un.h>
17 #include <sys/mman.h>
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <sys/time.h>
24 #include <dirent.h>
25 #include <sys/stat.h>
26 #include <signal.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <math.h>
30 #include <gdk/gdkkeysyms.h>
31
32
33 #ifdef USE_WEBKIT
34 #include <webkit2/webkit2.h>
35 #endif
36
37 #include <gdk-pixbuf/gdk-pixbuf.h>
38
39 #if __STDC_VERSION__ < 199901L
40 # if __GNUC__ >= 2
41 # define __func__ __FUNCTION__
42 # else
43 # define __func__ "<unknown>"
44 # endif
45 #endif
46
47 /* ff = 255 = 1.0000
48 * ee = 238 = 0.9333
49 * cc = 204 = 0.8000
50 * bb = 187 = 0.7333
51 * aa = 170 = 0.6667
52 * 77 = 119 = 0.4667
53 * 00 = 0 = 0.0000
54 */
55 GdkRGBA _colors[] =
56 {
57 { 0.0000, 0.0000, 0.0000, 1.0 }, /* 0 black */
58 { 0.7333, 0.0000, 0.0000, 1.0 }, /* 1 red */
59 { 0.0000, 0.7333, 0.0000, 1.0 }, /* 2 green */
60 { 0.6667, 0.6667, 0.0000, 1.0 }, /* 3 yellow */
61 { 0.0000, 0.0000, 0.8000, 1.0 }, /* 4 blue */
62 { 0.7333, 0.0000, 0.7333, 1.0 }, /* 5 magenta */
63 { 0.0000, 0.7333, 0.7333, 1.0 }, /* 6 cyan */
64 { 0.7333, 0.7333, 0.7333, 1.0 }, /* 7 white */
65 { 0.4667, 0.4667, 0.4667, 1.0 }, /* 8 grey */
66 { 1.0000, 0.0000, 0.0000, 1.0 }, /* 9 bright red */
67 { 0.0000, 1.0000, 0.0000, 1.0 }, /* 10 bright green */
68 { 0.9333, 0.9333, 0.0000, 1.0 }, /* 11 bright yellow */
69 { 0.0000, 0.0000, 1.0000, 1.0 }, /* 12 bright blue */
70 { 1.0000, 0.0000, 1.0000, 1.0 }, /* 13 bright magenta */
71 { 0.0000, 0.9333, 0.9333, 1.0 }, /* 14 bright cyan */
72 { 1.0000, 1.0000, 1.0000, 1.0 }, /* 15 bright white */
73 };
74
75 /*
76 * List those icons that have transparency first
77 */
78 #define NUM_EXTS 9
79 char *image_exts[NUM_EXTS] =
80 {
81 ".xpm",
82 ".png",
83 ".ico",
84 ".icns",
85 ".gif",
86 ".jpg",
87 ".jpeg",
88 ".tiff",
89 ".bmp"
90 };
91
92 #ifndef max
93 # define max(a,b) (((a) > (b)) ? (a) : (b))
94 #endif
95
96 #ifndef min
97 # define min(a,b) (((a) < (b)) ? (a) : (b))
98 #endif
99
100 pthread_key_t _dw_fg_color_key;
101 pthread_key_t _dw_bg_color_key;
102
103 GtkWidget *last_window = NULL, *popup = NULL;
104
105 static int _dw_ignore_click = 0, _dw_ignore_expand = 0;
106 static pthread_t _dw_thread = (pthread_t)-1;
107
108 #define DEFAULT_SIZE_WIDTH 12
109 #define DEFAULT_SIZE_HEIGHT 6
110 #define DEFAULT_TITLEBAR_HEIGHT 22
111
112 #define _DW_TREE_TYPE_CONTAINER 1
113 #define _DW_TREE_TYPE_TREE 2
114 #define _DW_TREE_TYPE_LISTBOX 3
115 #define _DW_TREE_TYPE_COMBOBOX 4
116
117 /* Signal forwarder prototypes */
118 static gint _button_press_event(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data);
119 static gint _button_release_event(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data);
120 static gint _motion_notify_event(GtkEventControllerMotion *controller, double x, double y, gpointer data);
121 static gint _delete_event(GtkWidget *widget, gpointer data);
122 static gint _key_press_event(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer data);
123 static gint _generic_event(GtkWidget *widget, gpointer data);
124 static gint _configure_event(GtkWidget *widget, GdkEvent *event, gpointer data);
125 static gint _activate_event(GtkWidget *widget, gpointer data);
126 static gint _container_enter_event(GtkWidget *widget, GdkEvent *event, gpointer data);
127 static gint _combobox_select_event(GtkWidget *widget, gpointer data);
128 static gint _expose_event(GtkWidget *widget, cairo_t *cr, gpointer data);
129 static gint _set_focus_event(GtkWindow *window, GtkWidget *widget, gpointer data);
130 static gint _tree_context_event(GtkWidget *widget, GdkEvent *event, gpointer data);
131 static gint _value_changed_event(GtkWidget *widget, gpointer user_data);
132 static gint _tree_select_event(GtkTreeSelection *sel, gpointer data);
133 static gint _tree_expand_event(GtkTreeView *treeview, GtkTreeIter *arg1, GtkTreePath *arg2, gpointer data);
134 static gint _switch_page_event(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer data);
135 static gint _column_click_event(GtkWidget *widget, gpointer data);
136 static void _html_result_event(GObject *object, GAsyncResult *result, gpointer script_data);
137 #ifdef USE_WEBKIT
138 static void _html_changed_event(WebKitWebView *web_view, WebKitLoadEvent load_event, gpointer data);
139 #endif
140 static void _dw_signal_disconnect(gpointer data, GClosure *closure);
141
142 GObject *_DWObject = NULL;
143 GApplication *_DWApp = NULL;
144 static char _dw_app_id[_DW_APP_ID_SIZE+1] = { 0 };
145 char *_DWDefaultFont = NULL;
146 static char _dw_share_path[PATH_MAX+1] = { 0 };
147
148 typedef struct
149 {
150 void *func;
151 char name[30];
152
153 } SignalList;
154
155 typedef struct
156 {
157 HWND window;
158 void *func;
159 gpointer data;
160 gint cid;
161 void *intfunc;
162
163 } SignalHandler;
164
165 #define SIGNALMAX 20
166
167 /* A list of signal forwarders, to account for paramater differences. */
168 static SignalList SignalTranslate[SIGNALMAX] = {
169 { _configure_event, DW_SIGNAL_CONFIGURE },
170 { _key_press_event, DW_SIGNAL_KEY_PRESS },
171 { _button_press_event, DW_SIGNAL_BUTTON_PRESS },
172 { _button_release_event, DW_SIGNAL_BUTTON_RELEASE },
173 { _motion_notify_event, DW_SIGNAL_MOTION_NOTIFY },
174 { _delete_event, DW_SIGNAL_DELETE },
175 { _expose_event, DW_SIGNAL_EXPOSE },
176 { _activate_event, "activate" },
177 { _generic_event, DW_SIGNAL_CLICKED },
178 { _container_enter_event, DW_SIGNAL_ITEM_ENTER },
179 { _tree_context_event, DW_SIGNAL_ITEM_CONTEXT },
180 { _combobox_select_event, DW_SIGNAL_LIST_SELECT },
181 { _tree_select_event, DW_SIGNAL_ITEM_SELECT },
182 { _set_focus_event, DW_SIGNAL_SET_FOCUS },
183 { _value_changed_event, DW_SIGNAL_VALUE_CHANGED },
184 { _switch_page_event, DW_SIGNAL_SWITCH_PAGE },
185 { _column_click_event, DW_SIGNAL_COLUMN_CLICK },
186 { _tree_expand_event, DW_SIGNAL_TREE_EXPAND },
187 #ifdef USE_WEBKIT
188 { _html_changed_event, DW_SIGNAL_HTML_CHANGED },
189 #else
190 { _generic_event, DW_SIGNAL_HTML_CHANGED },
191 #endif
192 { _html_result_event, DW_SIGNAL_HTML_RESULT }
193 };
194
195 /* Alignment flags */
196 #define DW_CENTER 0.5f
197 #define DW_LEFT 0.0f
198 #define DW_RIGHT 1.0f
199 #define DW_TOP 0.0f
200 #define DW_BOTTOM 1.0f
201
202 static void _dw_msleep(long period)
203 {
204 #ifdef __sun__
205 /* usleep() isn't threadsafe on Solaris */
206 struct timespec req;
207
208 req.tv_sec = 0;
209 if(period >= 1000)
210 {
211 req.tv_sec = (int)(period / 1000);
212 period -= (req.tv_sec * 1000);
213 }
214 req.tv_nsec = period * 10000000;
215
216 nanosleep(&req, NULL);
217 #else
218 usleep(period * 1000);
219 #endif
220 }
221
222 /* Finds the translation function for a given signal name */
223 static void *_findsigfunc(const char *signame)
224 {
225 int z;
226
227 for(z=0;z<SIGNALMAX;z++)
228 {
229 if(strcasecmp(signame, SignalTranslate[z].name) == 0)
230 return SignalTranslate[z].func;
231 }
232 return NULL;
233 }
234
235 static SignalHandler _get_signal_handler(gpointer data)
236 {
237 SignalHandler sh = {0};
238
239 if(data)
240 {
241 void **params = (void **)data;
242 int counter = GPOINTER_TO_INT(params[0]);
243 GtkWidget *widget = (GtkWidget *)params[2];
244 char text[100];
245
246 sprintf(text, "_dw_sigwindow%d", counter);
247 sh.window = (HWND)g_object_get_data(G_OBJECT(widget), text);
248 sprintf(text, "_dw_sigfunc%d", counter);
249 sh.func = (void *)g_object_get_data(G_OBJECT(widget), text);
250 sprintf(text, "_dw_intfunc%d", counter);
251 sh.intfunc = (void *)g_object_get_data(G_OBJECT(widget), text);
252 sprintf(text, "_dw_sigdata%d", counter);
253 sh.data = g_object_get_data(G_OBJECT(widget), text);
254 sprintf(text, "_dw_sigcid%d", counter);
255 sh.cid = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), text));
256 }
257 return sh;
258 }
259
260 static void _remove_signal_handler(GtkWidget *widget, int counter)
261 {
262 char text[100];
263 gint cid;
264
265 sprintf(text, "_dw_sigcid%d", counter);
266 cid = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), text));
267 g_signal_handler_disconnect(G_OBJECT(widget), cid);
268 g_object_set_data(G_OBJECT(widget), text, NULL);
269 sprintf(text, "_dw_sigwindow%d", counter);
270 g_object_set_data(G_OBJECT(widget), text, NULL);
271 sprintf(text, "_dw_sigfunc%d", counter);
272 g_object_set_data(G_OBJECT(widget), text, NULL);
273 sprintf(text, "_dw_intfunc%d", counter);
274 g_object_set_data(G_OBJECT(widget), text, NULL);
275 sprintf(text, "_dw_sigdata%d", counter);
276 g_object_set_data(G_OBJECT(widget), text, NULL);
277 }
278
279 static int _set_signal_handler(GtkWidget *widget, HWND window, void *func, gpointer data, void *intfunc, void *discfunc)
280 {
281 int counter = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "_dw_sigcounter"));
282 char text[100];
283
284 sprintf(text, "_dw_sigwindow%d", counter);
285 g_object_set_data(G_OBJECT(widget), text, (gpointer)window);
286 sprintf(text, "_dw_sigfunc%d", counter);
287 g_object_set_data(G_OBJECT(widget), text, (gpointer)func);
288 sprintf(text, "_dw_intfunc%d", counter);
289 g_object_set_data(G_OBJECT(widget), text, (gpointer)intfunc);
290 sprintf(text, "_dw_discfunc%d", counter);
291 g_object_set_data(G_OBJECT(widget), text, (gpointer)discfunc);
292 sprintf(text, "_dw_sigdata%d", counter);
293 g_object_set_data(G_OBJECT(widget), text, (gpointer)data);
294
295 counter++;
296 g_object_set_data(G_OBJECT(widget), "_dw_sigcounter", GINT_TO_POINTER(counter));
297
298 return counter - 1;
299 }
300
301 static void _set_signal_handler_id(GtkWidget *widget, int counter, gint cid)
302 {
303 char text[100];
304
305 sprintf(text, "_dw_sigcid%d", counter);
306 g_object_set_data(G_OBJECT(widget), text, GINT_TO_POINTER(cid));
307 }
308
309 static void _html_result_event(GObject *object, GAsyncResult *result, gpointer script_data)
310 {
311 #ifdef USE_WEBKIT
312 pthread_t saved_thread = _dw_thread;
313 WebKitJavascriptResult *js_result;
314 JSCValue *value;
315 GError *error = NULL;
316 int (*htmlresultfunc)(HWND, int, char *, void *, void *) = NULL;
317 gint handlerdata = GPOINTER_TO_INT(g_object_get_data(object, "_dw_html_result_id"));
318 void *user_data = NULL;
319
320 _dw_thread = (pthread_t)-1;
321 if(handlerdata)
322 {
323 SignalHandler work;
324 void *params[3] = { GINT_TO_POINTER(handlerdata-1), 0, object };
325
326 work = _get_signal_handler(params);
327
328 if(work.window)
329 {
330 htmlresultfunc = work.func;
331 user_data = work.data;
332 }
333 }
334
335 if(!(js_result = webkit_web_view_run_javascript_finish(WEBKIT_WEB_VIEW(object), result, &error)))
336 {
337 if(htmlresultfunc)
338 htmlresultfunc((HWND)object, DW_ERROR_UNKNOWN, error->message, script_data, user_data);
339 g_error_free (error);
340 _dw_thread = saved_thread;
341 return;
342 }
343
344 value = webkit_javascript_result_get_js_value(js_result);
345 if(jsc_value_is_string(value))
346 {
347 gchar *str_value = jsc_value_to_string(value);
348 JSCException *exception = jsc_context_get_exception(jsc_value_get_context(value));
349
350 if(htmlresultfunc)
351 {
352 if(exception)
353 htmlresultfunc((HWND)object, DW_ERROR_UNKNOWN, (char *)jsc_exception_get_message(exception), script_data, user_data);
354 else
355 htmlresultfunc((HWND)object, DW_ERROR_NONE, str_value, script_data, user_data);
356 }
357 g_free (str_value);
358 }
359 else if(htmlresultfunc)
360 htmlresultfunc((HWND)object, DW_ERROR_UNKNOWN, NULL, script_data, user_data);
361 webkit_javascript_result_unref (js_result);
362 _dw_thread = saved_thread;
363 #endif
364 }
365
366 #ifdef USE_WEBKIT
367 static void _html_changed_event(WebKitWebView *web_view, WebKitLoadEvent load_event, gpointer data)
368 {
369 SignalHandler work = _get_signal_handler(data);
370 char *location = (char *)webkit_web_view_get_uri(web_view);
371 int status = 0;
372
373 switch (load_event) {
374 case WEBKIT_LOAD_STARTED:
375 status = DW_HTML_CHANGE_STARTED;
376 break;
377 case WEBKIT_LOAD_REDIRECTED:
378 status = DW_HTML_CHANGE_REDIRECT;
379 break;
380 case WEBKIT_LOAD_COMMITTED:
381 status = DW_HTML_CHANGE_LOADING;
382 break;
383 case WEBKIT_LOAD_FINISHED:
384 status = DW_HTML_CHANGE_COMPLETE;
385 break;
386 }
387 if(status && location && work.window && work.func)
388 {
389 int (*htmlchangedfunc)(HWND, int, char *, void *) = work.func;
390
391 htmlchangedfunc(work.window, status, location, work.data);
392 }
393 }
394 #endif
395
396 static gint _set_focus_event(GtkWindow *window, GtkWidget *widget, gpointer data)
397 {
398 SignalHandler work = _get_signal_handler(data);
399 int retval = FALSE;
400
401 if(work.window)
402 {
403 int (*setfocusfunc)(HWND, void *) = work.func;
404
405 retval = setfocusfunc(work.window, work.data);
406 }
407 return retval;
408 }
409
410 static gint _button_press_event(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
411 {
412 SignalHandler work = _get_signal_handler(data);
413 int retval = FALSE;
414
415 if(work.window)
416 {
417 int (*buttonfunc)(HWND, int, int, int, void *) = work.func;
418 /* TODO: Fill these in */
419 int mybutton = 1;
420
421 #if GTK3
422 if(event->button == 3)
423 mybutton = 2;
424 else if(event->button == 2)
425 mybutton = 3;
426 #endif
427
428 retval = buttonfunc(work.window, (int)x, (int)y, mybutton, work.data);
429 }
430 return retval;
431 }
432
433 static gint _button_release_event(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
434 {
435 SignalHandler work = _get_signal_handler(data);
436 int retval = FALSE;
437
438 if(work.window)
439 {
440 int (*buttonfunc)(HWND, int, int, int, void *) = work.func;
441 /* TODO: Fill these in */
442 int mybutton = 1;
443
444 #if GTK3
445 if(event->button == 3)
446 mybutton = 2;
447 else if(event->button == 2)
448 mybutton = 3;
449 #endif
450
451 retval = buttonfunc(work.window, (int)x, (int)y, mybutton, work.data);
452 }
453 return retval;
454 }
455
456 static gint _motion_notify_event(GtkEventControllerMotion *controller, double x, double y, gpointer data)
457 {
458 SignalHandler work = _get_signal_handler(data);
459 int retval = FALSE;
460
461 if(work.window)
462 {
463 int (*motionfunc)(HWND, int, int, int, void *) = work.func;
464 int keys = 0;
465 /* TODO: Fill these in */
466 GdkModifierType state = 0;
467
468 if (state & GDK_BUTTON1_MASK)
469 keys = DW_BUTTON1_MASK;
470 if (state & GDK_BUTTON3_MASK)
471 keys |= DW_BUTTON2_MASK;
472 if (state & GDK_BUTTON2_MASK)
473 keys |= DW_BUTTON3_MASK;
474
475 retval = motionfunc(work.window, (int)x, (int)y, keys, work.data);
476 }
477 return retval;
478 }
479
480 static gint _delete_event(GtkWidget *widget, gpointer data)
481 {
482 SignalHandler work = _get_signal_handler(data);
483 int retval = FALSE;
484
485 if(work.window)
486 {
487 int (*closefunc)(HWND, void *) = work.func;
488
489 retval = closefunc(work.window, work.data);
490 }
491 return retval;
492 }
493
494 static gint _key_press_event(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer data)
495 {
496 SignalHandler work = _get_signal_handler(data);
497 int retval = FALSE;
498
499 if(work.window)
500 {
501 int (*keypressfunc)(HWND, char, int, int, void *, char *) = work.func;
502 guint32 unichar = gdk_keyval_to_unicode(keyval);
503 char utf8[7] = { 0 };
504
505 g_unichar_to_utf8(unichar, utf8);
506
507 retval = keypressfunc(work.window, (char)keycode, keyval,
508 state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_ALT_MASK), work.data, utf8);
509 }
510 return retval;
511 }
512
513 static gint _generic_event(GtkWidget *widget, gpointer data)
514 {
515 SignalHandler work = _get_signal_handler(data);
516 int retval = FALSE;
517
518 if(work.window)
519 {
520 int (*genericfunc)(HWND, void *) = work.func;
521
522 retval = genericfunc(work.window, work.data);
523 }
524 return retval;
525 }
526
527 static gint _activate_event(GtkWidget *widget, gpointer data)
528 {
529 SignalHandler work = _get_signal_handler(data);
530 int retval = FALSE;
531
532 if(work.window && !_dw_ignore_click)
533 {
534 int (*activatefunc)(HWND, void *) = work.func;
535
536 retval = activatefunc(popup ? popup : work.window, work.data);
537 popup = NULL;
538 }
539 return retval;
540 }
541
542 static gint _configure_event(GtkWidget *widget, GdkEvent *event, gpointer data)
543 {
544 SignalHandler work = _get_signal_handler(data);
545 int retval = FALSE;
546
547 if(work.window)
548 {
549 int (*sizefunc)(HWND, int, int, void *) = work.func;
550
551 retval = sizefunc(work.window, 100, 100, work.data);
552 }
553 return retval;
554 }
555
556 static gint _expose_event(GtkWidget *widget, cairo_t *cr, gpointer data)
557 {
558 SignalHandler work = _get_signal_handler(data);
559 int retval = FALSE;
560
561 if(work.window)
562 {
563 DWExpose exp;
564 int (*exposefunc)(HWND, DWExpose *, void *) = work.func;
565
566 exp.x = exp.y = 0;
567 exp.width = gtk_widget_get_allocated_width(widget);
568 exp.height = gtk_widget_get_allocated_height(widget);
569 retval = exposefunc(work.window, &exp, work.data);
570 }
571 return retval;
572 }
573
574 static gint _combobox_select_event(GtkWidget *widget, gpointer data)
575 {
576 SignalHandler work = _get_signal_handler(data);
577 int retval = FALSE;
578
579 if(g_object_get_data(G_OBJECT(widget), "_dw_recursing"))
580 return FALSE;
581
582 if(work.window && GTK_IS_COMBO_BOX(widget))
583 {
584 GtkTreeModel *store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
585
586 if(store)
587 {
588 GtkTreeIter iter;
589 GtkTreePath *path;
590
591 g_object_set_data(G_OBJECT(widget), "_dw_recursing", GINT_TO_POINTER(1));
592
593 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
594 {
595 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
596
597 if(path)
598 {
599 gint *indices = gtk_tree_path_get_indices(path);
600
601 if(indices)
602 {
603 int (*selectfunc)(HWND, int, void *) = work.func;
604
605 retval = selectfunc(work.window, indices[0], work.data);
606 }
607 gtk_tree_path_free(path);
608 }
609 }
610
611 g_object_set_data(G_OBJECT(widget), "_dw_recursing", NULL);
612 }
613 }
614 return retval;
615 }
616
617 #define _DW_DATA_TYPE_STRING 0
618 #define _DW_DATA_TYPE_POINTER 1
619
620 static gint _tree_context_event(GtkWidget *widget, GdkEvent *event, gpointer data)
621 {
622 SignalHandler work = _get_signal_handler(data);
623 int retval = FALSE;
624
625 if(work.window)
626 {
627 int button = 1;
628
629 if(button == 3)
630 {
631 int (*contextfunc)(HWND, char *, int, int, void *, void *) = work.func;
632 char *text = NULL;
633 void *itemdata = NULL;
634 /* TODO: Fill these in */
635 int x = 0, y = 0;
636
637 if(widget && GTK_IS_TREE_VIEW(widget))
638 {
639 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
640 GtkTreeModel *store = (GtkTreeModel *)gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
641 GtkTreeIter iter;
642
643 if(sel && gtk_tree_selection_get_mode(sel) != GTK_SELECTION_MULTIPLE &&
644 gtk_tree_selection_get_selected(sel, NULL, &iter))
645 {
646 if(g_object_get_data(G_OBJECT(widget), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_TREE))
647 {
648 gtk_tree_model_get(store, &iter, _DW_DATA_TYPE_STRING, &text, 2, &itemdata, -1);
649 }
650 else
651 {
652 gtk_tree_model_get(store, &iter, _DW_DATA_TYPE_STRING, &text, -1);
653 }
654 }
655 else
656 {
657 GtkTreePath *path;
658
659 gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, NULL);
660 if(path)
661 {
662 GtkTreeIter iter;
663
664 if(gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
665 {
666 if(g_object_get_data(G_OBJECT(widget), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_TREE))
667 {
668 gtk_tree_model_get(store, &iter, _DW_DATA_TYPE_STRING, &text, 2, &itemdata, -1);
669 }
670 else
671 {
672 gtk_tree_model_get(store, &iter, _DW_DATA_TYPE_STRING, &text, -1);
673 }
674 }
675 gtk_tree_path_free(path);
676 }
677 }
678 }
679
680 retval = contextfunc(work.window, text, x, y, work.data, itemdata);
681 if(text)
682 g_free(text);
683 }
684 }
685 return retval;
686 }
687
688 static gint _tree_select_event(GtkTreeSelection *sel, gpointer data)
689 {
690 GtkWidget *item = NULL, *widget = (GtkWidget *)gtk_tree_selection_get_tree_view(sel);
691 int retval = FALSE;
692
693 if(widget)
694 {
695 SignalHandler work = _get_signal_handler(data);
696
697 if(work.window)
698 {
699 int (*treeselectfunc)(HWND, HTREEITEM, char *, void *, void *) = work.func;
700 GtkTreeIter iter;
701 char *text = NULL;
702 void *itemdata = NULL;
703 GtkTreeModel *store = (GtkTreeModel *)gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
704
705 if(g_object_get_data(G_OBJECT(widget), "_dw_double_click"))
706 {
707 g_object_set_data(G_OBJECT(widget), "_dw_double_click", GINT_TO_POINTER(0));
708 return TRUE;
709 }
710
711 if(gtk_tree_selection_get_mode(sel) != GTK_SELECTION_MULTIPLE &&
712 gtk_tree_selection_get_selected(sel, NULL, &iter))
713 {
714 if(g_object_get_data(G_OBJECT(widget), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_TREE))
715 {
716 gtk_tree_model_get(store, &iter, _DW_DATA_TYPE_STRING, &text, 2, &itemdata, 3, &item, -1);
717 retval = treeselectfunc(work.window, (HTREEITEM)item, text, work.data, itemdata);
718 }
719 else if(g_object_get_data(G_OBJECT(widget), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
720 {
721 gtk_tree_model_get(store, &iter, _DW_DATA_TYPE_STRING, &text, _DW_DATA_TYPE_POINTER, &itemdata, -1);
722 retval = treeselectfunc(work.window, (HTREEITEM)item, text, work.data, itemdata);
723 }
724 else
725 {
726 GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
727
728 if(path)
729 {
730 gint *indices = gtk_tree_path_get_indices(path);
731
732 if(indices)
733 {
734 int (*selectfunc)(HWND, int, void *) = work.func;
735
736 retval = selectfunc(work.window, indices[0], work.data);
737 }
738 gtk_tree_path_free(path);
739 }
740 }
741 }
742 else
743 {
744 GtkTreePath *path;
745
746 gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, NULL);
747 if(path)
748 {
749 GtkTreeIter iter;
750
751 if(gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
752 {
753 if(g_object_get_data(G_OBJECT(widget), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_TREE))
754 {
755 gtk_tree_model_get(store, &iter, _DW_DATA_TYPE_STRING, &text, 2, &itemdata, 3, &item, -1);
756 retval = treeselectfunc(work.window, (HTREEITEM)item, text, work.data, itemdata);
757 }
758 else if(g_object_get_data(G_OBJECT(widget), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
759 {
760 gtk_tree_model_get(store, &iter, _DW_DATA_TYPE_STRING, &text, _DW_DATA_TYPE_POINTER, &itemdata, -1);
761 retval = treeselectfunc(work.window, (HTREEITEM)item, text, work.data, itemdata);
762 }
763 else
764 {
765 gint *indices = gtk_tree_path_get_indices(path);
766
767 if(indices)
768 {
769 int (*selectfunc)(HWND, int, void *) = work.func;
770
771 retval = selectfunc(work.window, indices[0], work.data);
772 }
773 }
774 }
775 gtk_tree_path_free(path);
776 }
777 }
778 if(text)
779 g_free(text);
780 }
781 }
782 return retval;
783 }
784
785 static gint _tree_expand_event(GtkTreeView *widget, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
786 {
787 SignalHandler work = _get_signal_handler(data);
788 int retval = FALSE;
789
790 if(!_dw_ignore_expand && work.window)
791 {
792 int (*treeexpandfunc)(HWND, HTREEITEM, void *) = work.func;
793 retval = treeexpandfunc(work.window, (HTREEITEM)iter, work.data);
794 }
795 return retval;
796 }
797
798 static gint _container_enter_event(GtkWidget *widget, GdkEvent *event, gpointer data)
799 {
800 SignalHandler work = _get_signal_handler(data);
801 int retval = FALSE;
802
803 if(work.window)
804 {
805 /* Handle both key and button events together */
806 if(retval /* TODO: Fix this...
807 (event->type == GDK_2BUTTON_PRESS && buttonevent->button == 1) ||
808 (event->type == GDK_KEY_PRESS && keyevent->keyval == VK_RETURN)*/)
809 {
810 int (*contextfunc)(HWND, char *, void *, void *) = work.func;
811 char *text = NULL;
812 void *data = NULL;
813
814 /* Sanity check */
815 if(GTK_IS_TREE_VIEW(widget))
816 {
817 GtkTreePath *path;
818 GtkTreeModel *store = (GtkTreeModel *)gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
819
820 gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, NULL);
821 if(path)
822 {
823 GtkTreeIter iter;
824
825 if(gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
826 {
827 if(g_object_get_data(G_OBJECT(widget), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
828 {
829 gtk_tree_model_get(store, &iter, _DW_DATA_TYPE_STRING, &text, _DW_DATA_TYPE_POINTER, &data, -1);
830 retval = contextfunc(work.window, text, work.data, data);
831 if(text)
832 g_free(text);
833 }
834 }
835 gtk_tree_path_free(path);
836 }
837 }
838 }
839 }
840 return retval;
841 }
842
843 /* Return the logical page id from the physical page id */
844 int _get_logical_page(HWND handle, unsigned long pageid)
845 {
846 int z;
847 GtkWidget **pagearray = g_object_get_data(G_OBJECT(handle), "_dw_pagearray");
848 GtkWidget *thispage = gtk_notebook_get_nth_page(GTK_NOTEBOOK(handle), pageid);
849
850 if(pagearray && thispage)
851 {
852 for(z=0;z<256;z++)
853 {
854 if(thispage == pagearray[z])
855 return z;
856 }
857 }
858 return 256;
859 }
860
861
862 static gint _switch_page_event(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer data)
863 {
864 SignalHandler work = _get_signal_handler(data);
865 int retval = FALSE;
866
867 if(work.window)
868 {
869 int (*switchpagefunc)(HWND, unsigned long, void *) = work.func;
870 retval = switchpagefunc(work.window, _get_logical_page(GTK_WIDGET(notebook), page_num), work.data);
871 }
872 return retval;
873 }
874
875 static gint _column_click_event(GtkWidget *widget, gpointer data)
876 {
877 void **params = data;
878 int retval = FALSE;
879
880 if(params && params[2])
881 {
882 GtkWidget *tree = (GtkWidget *)params[2];
883 gint handlerdata = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tree), "_dw_column_click_id"));
884
885 if(handlerdata)
886 {
887 SignalHandler work;
888
889 params[0] = GINT_TO_POINTER(handlerdata-1);
890 work = _get_signal_handler(params);
891
892 if(work.window)
893 {
894 int column_num = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "_dw_column"));
895 int (*clickcolumnfunc)(HWND, int, void *) = work.func;
896 retval = clickcolumnfunc(work.window, column_num, work.data);
897 }
898 }
899 }
900 return retval;
901 }
902
903 static int _round_value(gfloat val)
904 {
905 int newval = (int)val;
906
907 if(val >= 0.5 + (gfloat)newval)
908 newval++;
909
910 return newval;
911 }
912
913 static gint _value_changed_event(GtkWidget *widget, gpointer data)
914 {
915 GtkWidget *slider, *spinbutton, *scrollbar;
916 GtkAdjustment *adjustment = (GtkAdjustment *)widget;
917 int max, val;
918
919 if(!GTK_IS_ADJUSTMENT(adjustment))
920 adjustment = (GtkAdjustment *)g_object_get_data(G_OBJECT(widget), "_dw_adjustment");
921
922 slider = (GtkWidget *)g_object_get_data(G_OBJECT(adjustment), "_dw_slider");
923 spinbutton = (GtkWidget *)g_object_get_data(G_OBJECT(adjustment), "_dw_spinbutton");
924 scrollbar = (GtkWidget *)g_object_get_data(G_OBJECT(adjustment), "_dw_scrollbar");
925
926 max = _round_value(gtk_adjustment_get_upper(adjustment));
927 val = _round_value(gtk_adjustment_get_value(adjustment));
928
929 if(g_object_get_data(G_OBJECT(adjustment), "_dw_suppress_value_changed_event"))
930 return FALSE;
931
932 if (slider || spinbutton || scrollbar)
933 {
934 SignalHandler work = _get_signal_handler(data);
935
936 if (work.window)
937 {
938 int (*valuechangedfunc)(HWND, int, void *) = work.func;
939
940 if(slider && gtk_orientable_get_orientation(GTK_ORIENTABLE(slider)) == GTK_ORIENTATION_VERTICAL)
941 valuechangedfunc(work.window, (max - val) - 1, work.data);
942 else
943 valuechangedfunc(work.window, val, work.data);
944 }
945 }
946 return FALSE;
947 }
948
949 static gint _default_key_press_event(GtkWidget *widget, GdkEvent *event, gpointer data)
950 {
951 GtkWidget *next = (GtkWidget *)data;
952
953 if(next)
954 {
955 if(0 /* TODO: Fix this: event->keyval == GDK_KEY_Return*/)
956 {
957 if(GTK_IS_BUTTON(next))
958 g_signal_emit_by_name(G_OBJECT(next), "clicked");
959 else
960 gtk_widget_grab_focus(next);
961 }
962 }
963 return FALSE;
964 }
965
966 static GdkPixbuf *_dw_pixbuf_from_resource(unsigned int rid)
967 {
968 char resource_path[201] = {0};
969 snprintf(resource_path, 200, "/org/dbsoft/dwindows/resources/%u.png", rid);
970 return gdk_pixbuf_new_from_resource(resource_path, NULL);
971 }
972
973 static GdkPixbuf *_find_pixbuf(HICN icon, unsigned long *userwidth, unsigned long *userheight)
974 {
975 unsigned int id = GPOINTER_TO_INT(icon);
976 GdkPixbuf *icon_pixbuf = NULL;
977
978 /* Quick dropout for non-handle */
979 if(!icon)
980 return NULL;
981
982 if(id > 65535)
983 icon_pixbuf = icon;
984 else
985 icon_pixbuf = _dw_pixbuf_from_resource(id);
986
987 if(userwidth)
988 *userwidth = icon_pixbuf ? gdk_pixbuf_get_width(icon_pixbuf) : 0;
989 if(userheight)
990 *userheight = icon_pixbuf ? gdk_pixbuf_get_height(icon_pixbuf) : 0;
991
992 return icon_pixbuf;
993 }
994
995 /* Handle system notification click callbacks */
996 static void _dw_notification_handler(GSimpleAction *action, GVariant *param, gpointer user_data)
997 {
998 char textbuf[101] = {0};
999 int (*func)(HWND, void *);
1000 void *data;
1001
1002 snprintf(textbuf, 100, "dw-notification-%llu-func", DW_POINTER_TO_ULONGLONG(g_variant_get_uint64(param)));
1003 func = g_object_get_data(G_OBJECT(_DWApp), textbuf);
1004 g_object_set_data(G_OBJECT(_DWApp), textbuf, NULL);
1005 snprintf(textbuf, 100, "dw-notification-%llu-data", DW_POINTER_TO_ULONGLONG(g_variant_get_uint64(param)));
1006 data = g_object_get_data(G_OBJECT(_DWApp), textbuf);
1007 g_object_set_data(G_OBJECT(_DWApp), textbuf, NULL);
1008
1009 if(func)
1010 func((HWND)DW_ULONGLONG_TO_POINTER(g_variant_get_uint64(param)), data);
1011 }
1012
1013 static void _dw_app_activate(GApplication *app, gpointer user_data)
1014 {
1015 /* Not sure why this signal is required, but GLib gives warnings
1016 * when this signal is not connected, so putting this here to
1017 * quell the warning and can be used at a later point if needed.
1018 */
1019 }
1020
1021 /*
1022 * Initializes the Dynamic Windows engine.
1023 * Parameters:
1024 * newthread: True if this is the only thread.
1025 * False if there is already a message loop running.
1026 */
1027 int dw_init(int newthread, int argc, char *argv[])
1028 {
1029 /* Setup the private data directory */
1030 if(argc > 0 && argv[0])
1031 {
1032 char *pathcopy = strdup(argv[0]);
1033 char *pos = strrchr(pathcopy, '/');
1034 char *binname = pathcopy;
1035
1036 /* If we have a / then...
1037 * the binary name should be at the end.
1038 */
1039 if(pos)
1040 {
1041 binname = pos + 1;
1042 *pos = 0;
1043 }
1044
1045 if(*binname)
1046 {
1047 char *binpos = strstr(pathcopy, "/bin");
1048
1049 if(binpos)
1050 strncpy(_dw_share_path, pathcopy, (size_t)(binpos - pathcopy));
1051 else
1052 strcpy(_dw_share_path, "/usr/local");
1053 strcat(_dw_share_path, "/share/");
1054 strcat(_dw_share_path, binname);
1055 if(!_dw_app_id[0])
1056 {
1057 /* If we have a binary name, use that for the Application ID instead. */
1058 snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.%s", DW_APP_DOMAIN_DEFAULT, binname);
1059 }
1060 }
1061 if(pathcopy)
1062 free(pathcopy);
1063 }
1064 /* If that failed... just get the current directory */
1065 if(!_dw_share_path[0] && !getcwd(_dw_share_path, PATH_MAX))
1066 _dw_share_path[0] = '/';
1067
1068 gtk_init();
1069
1070 pthread_key_create(&_dw_fg_color_key, NULL);
1071 pthread_key_create(&_dw_bg_color_key, NULL);
1072
1073 _dw_init_thread();
1074
1075 /* Create a global object for glib activities */
1076 _DWObject = g_object_new(G_TYPE_OBJECT, NULL);
1077
1078 if(!_dw_app_id[0])
1079 {
1080 /* Generate an Application ID based on the PID if all else fails. */
1081 snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.pid.%d", DW_APP_DOMAIN_DEFAULT, (int)getpid());
1082 }
1083
1084 /* Initialize the application subsystem on supported versions...
1085 * we generate an application ID based on the binary name or PID
1086 * instead of passing NULL to enable full application support.
1087 */
1088 _DWApp = g_application_new(_dw_app_id, G_APPLICATION_FLAGS_NONE);
1089 if(_DWApp && g_application_register(_DWApp, NULL, NULL))
1090 {
1091 /* Creat our notification handler for any notifications */
1092 GSimpleAction *action = g_simple_action_new("notification", G_VARIANT_TYPE_UINT64);
1093
1094 g_signal_connect(G_OBJECT(action), "activate", G_CALLBACK(_dw_notification_handler), NULL);
1095 g_action_map_add_action(G_ACTION_MAP(_DWApp), G_ACTION(action));
1096 g_signal_connect(_DWApp, "activate", G_CALLBACK(_dw_app_activate), NULL);
1097 g_application_activate(_DWApp);
1098 }
1099 return TRUE;
1100 }
1101
1102 /*
1103 * Runs a message loop for Dynamic Windows.
1104 */
1105 void API dw_main(void)
1106 {
1107 gtk_main();
1108 }
1109
1110 /*
1111 * Causes running dw_main() to return.
1112 */
1113 void API dw_main_quit(void)
1114 {
1115 gtk_main_quit();
1116 }
1117
1118 /*
1119 * Runs a message loop for Dynamic Windows, for a period of milliseconds.
1120 * Parameters:
1121 * milliseconds: Number of milliseconds to run the loop for.
1122 */
1123 void API dw_main_sleep(int milliseconds)
1124 {
1125 struct timeval tv, start;
1126 pthread_t curr = pthread_self();
1127
1128 gettimeofday(&start, NULL);
1129
1130 if(_dw_thread == (pthread_t)-1 || _dw_thread == curr)
1131 {
1132 pthread_t orig = _dw_thread;
1133
1134 gettimeofday(&tv, NULL);
1135
1136 while(((tv.tv_sec - start.tv_sec)*1000) + ((tv.tv_usec - start.tv_usec)/1000) <= milliseconds)
1137 {
1138 if(orig == (pthread_t)-1)
1139 _dw_thread = curr;
1140 if(curr == _dw_thread && gtk_events_pending())
1141 gtk_main_iteration();
1142 else
1143 _dw_msleep(1);
1144 if(orig == (pthread_t)-1)
1145 _dw_thread = orig;
1146 gettimeofday(&tv, NULL);
1147 }
1148 }
1149 else
1150 _dw_msleep(milliseconds);
1151 }
1152
1153 /*
1154 * Processes a single message iteration and returns.
1155 */
1156 void API dw_main_iteration(void)
1157 {
1158 pthread_t orig = _dw_thread;
1159 pthread_t curr = pthread_self();
1160
1161 if(_dw_thread == (pthread_t)-1)
1162 _dw_thread = curr;
1163 if(curr == _dw_thread && gtk_events_pending())
1164 gtk_main_iteration();
1165 else
1166 sched_yield();
1167 if(orig == (pthread_t)-1)
1168 _dw_thread = orig;
1169 }
1170
1171 /*
1172 * Free's memory allocated by dynamic windows.
1173 * Parameters:
1174 * ptr: Pointer to dynamic windows allocated
1175 * memory to be free()'d.
1176 */
1177 void dw_free(void *ptr)
1178 {
1179 free(ptr);
1180 }
1181
1182 /*
1183 * Allocates and initializes a dialog struct.
1184 * Parameters:
1185 * data: User defined data to be passed to functions.
1186 */
1187 DWDialog *dw_dialog_new(void *data)
1188 {
1189 DWDialog *tmp = malloc(sizeof(DWDialog));
1190
1191 if ( tmp )
1192 {
1193 tmp->eve = dw_event_new();
1194 dw_event_reset(tmp->eve);
1195 tmp->data = data;
1196 tmp->done = FALSE;
1197 tmp->method = FALSE;
1198 tmp->result = NULL;
1199 }
1200 return tmp;
1201 }
1202
1203 /*
1204 * Accepts a dialog struct and returns the given data to the
1205 * initial called of dw_dialog_wait().
1206 * Parameters:
1207 * dialog: Pointer to a dialog struct aquired by dw_dialog_new).
1208 * result: Data to be returned by dw_dialog_wait().
1209 */
1210 int dw_dialog_dismiss(DWDialog *dialog, void *result)
1211 {
1212 dialog->result = result;
1213 if(dialog->method)
1214 gtk_main_quit();
1215 else
1216 dw_event_post(dialog->eve);
1217 dialog->done = TRUE;
1218 return 0;
1219 }
1220
1221 /*
1222 * Accepts a dialog struct waits for dw_dialog_dismiss() to be
1223 * called by a signal handler with the given dialog struct.
1224 * Parameters:
1225 * dialog: Pointer to a dialog struct aquired by dw_dialog_new).
1226 */
1227 void *dw_dialog_wait(DWDialog *dialog)
1228 {
1229 void *tmp;
1230 int newprocess = 0;
1231
1232 if(!dialog)
1233 return NULL;
1234
1235 /* _dw_thread will be -1 if dw_main hasn't been run yet. */
1236 if(_dw_thread == (pthread_t)-1)
1237 {
1238 _dw_thread = pthread_self();
1239 newprocess = 1;
1240 _dw_gdk_threads_enter();
1241 }
1242
1243 if(pthread_self() == _dw_thread)
1244 {
1245 dialog->method = TRUE;
1246 gtk_main();
1247 }
1248 else
1249 {
1250 dialog->method = FALSE;
1251 dw_event_wait(dialog->eve, -1);
1252 }
1253
1254 if(newprocess)
1255 {
1256 _dw_thread = (pthread_t)-1;
1257 _dw_gdk_threads_leave();
1258 }
1259
1260 dw_event_close(&dialog->eve);
1261 tmp = dialog->result;
1262 free(dialog);
1263 return tmp;
1264 }
1265
1266 /*
1267 * Displays a debug message on the console...
1268 * Parameters:
1269 * format: printf style format string.
1270 * ...: Additional variables for use in the format.
1271 */
1272 void API dw_debug(const char *format, ...)
1273 {
1274 va_list args;
1275 char outbuf[1025] = {0};
1276
1277 va_start(args, format);
1278 vsnprintf(outbuf, 1024, format, args);
1279 va_end(args);
1280
1281 fprintf(stderr, "%s", outbuf);
1282 }
1283
1284 /*
1285 * Displays a Message Box with given text and title..
1286 * Parameters:
1287 * title: The title of the message box.
1288 * flags: Defines buttons and icons to display
1289 * format: printf style format string.
1290 * ...: Additional variables for use in the format.
1291 */
1292 int dw_messagebox(const char *title, int flags, const char *format, ...)
1293 {
1294 GtkMessageType gtkicon = GTK_MESSAGE_OTHER;
1295 GtkButtonsType gtkbuttons = GTK_BUTTONS_OK;
1296 GtkWidget *dialog;
1297 int response;
1298 va_list args;
1299 char outbuf[1025] = {0};
1300
1301 va_start(args, format);
1302 vsnprintf(outbuf, 1024, format, args);
1303 va_end(args);
1304
1305 if(flags & DW_MB_ERROR)
1306 gtkicon = GTK_MESSAGE_ERROR;
1307 else if(flags & DW_MB_WARNING)
1308 gtkicon = GTK_MESSAGE_WARNING;
1309 else if(flags & DW_MB_INFORMATION)
1310 gtkicon = GTK_MESSAGE_INFO;
1311 else if(flags & DW_MB_QUESTION)
1312 gtkicon = GTK_MESSAGE_QUESTION;
1313
1314 if(flags & DW_MB_OKCANCEL)
1315 gtkbuttons = GTK_BUTTONS_OK_CANCEL;
1316 else if(flags & (DW_MB_YESNO | DW_MB_YESNOCANCEL))
1317 gtkbuttons = GTK_BUTTONS_YES_NO;
1318
1319 dialog = gtk_message_dialog_new(NULL,
1320 GTK_DIALOG_USE_HEADER_BAR |
1321 GTK_DIALOG_MODAL, gtkicon, gtkbuttons, "%s", title);
1322 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", outbuf);
1323 if(flags & DW_MB_YESNOCANCEL)
1324 gtk_dialog_add_button(GTK_DIALOG(dialog), "Cancel", GTK_RESPONSE_CANCEL);
1325 response = gtk_dialog_run(GTK_DIALOG(dialog));
1326 gtk_widget_destroy(dialog);
1327 switch(response)
1328 {
1329 case GTK_RESPONSE_OK:
1330 return DW_MB_RETURN_OK;
1331 case GTK_RESPONSE_CANCEL:
1332 return DW_MB_RETURN_CANCEL;
1333 case GTK_RESPONSE_YES:
1334 return DW_MB_RETURN_YES;
1335 case GTK_RESPONSE_NO:
1336 return DW_MB_RETURN_NO;
1337 default:
1338 {
1339 /* Handle the destruction of the dialog result */
1340 if(flags & (DW_MB_OKCANCEL | DW_MB_YESNOCANCEL))
1341 return DW_MB_RETURN_CANCEL;
1342 else if(flags & DW_MB_YESNO)
1343 return DW_MB_RETURN_NO;
1344 }
1345 }
1346 return DW_MB_RETURN_OK;
1347 }
1348
1349 /*
1350 * Minimizes or Iconifies a top-level window.
1351 * Parameters:
1352 * handle: The window handle to minimize.
1353 */
1354 int dw_window_minimize(HWND handle)
1355 {
1356 if(!handle)
1357 return 0;
1358
1359 gtk_window_iconify( GTK_WINDOW(handle) );
1360 return 0;
1361 }
1362
1363 /*
1364 * Makes the window topmost.
1365 * Parameters:
1366 * handle: The window handle to make topmost.
1367 */
1368 int dw_window_raise(HWND handle)
1369 {
1370 if(!handle)
1371 return 0;
1372
1373 gdk_window_raise(gtk_widget_get_window(GTK_WIDGET(handle)));
1374 return 0;
1375 }
1376
1377 /*
1378 * Makes the window bottommost.
1379 * Parameters:
1380 * handle: The window handle to make bottommost.
1381 */
1382 int dw_window_lower(HWND handle)
1383 {
1384 if(!handle)
1385 return 0;
1386
1387 gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(handle)));
1388 return 0;
1389 }
1390
1391 /*
1392 * Makes the window visible.
1393 * Parameters:
1394 * handle: The window handle to make visible.
1395 */
1396 int dw_window_show(HWND handle)
1397 {
1398 GtkWidget *defaultitem;
1399
1400 if (!handle)
1401 return 0;
1402
1403 gtk_widget_show(handle);
1404 {
1405 GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(handle));
1406 if (window && gtk_widget_get_mapped(handle))
1407 {
1408 int width = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_width"));
1409 int height = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_height"));
1410
1411 /* If we had a size request before shown */
1412 if (width || height)
1413 {
1414 /* Call the size function again now that we are realized */
1415 dw_window_set_size(handle, width, height);
1416 /* Clear out the data so we don't do it again */
1417 g_object_set_data(G_OBJECT(handle), "_dw_width", NULL);
1418 g_object_set_data(G_OBJECT(handle), "_dw_height", NULL);
1419 }
1420
1421 /* If we had a position request before shown */
1422 if (g_object_get_data(G_OBJECT(handle), "_dw_pos"))
1423 {
1424 int x = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_x"));
1425 int y = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_y"));
1426
1427 /* Call the position function again now that we are realized */
1428 dw_window_set_pos(handle, x, y);
1429 /* Clear out the data so we don't do it again */
1430 g_object_set_data(G_OBJECT(handle), "_dw_pos", NULL);
1431 }
1432
1433 gdk_window_raise(window);
1434 gdk_display_flush(gdk_display_get_default());
1435 gdk_window_show(window);
1436 gdk_display_flush(gdk_display_get_default());
1437 }
1438 defaultitem = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_defaultitem");
1439 if (defaultitem)
1440 gtk_widget_grab_focus(defaultitem);
1441 }
1442 return 0;
1443 }
1444
1445 /*
1446 * Makes the window invisible.
1447 * Parameters:
1448 * handle: The window handle to make visible.
1449 */
1450 int dw_window_hide(HWND handle)
1451 {
1452 if(!handle)
1453 return 0;
1454
1455 gtk_widget_hide(handle);
1456 return 0;
1457 }
1458
1459 /*
1460 * Destroys a window and all of it's children.
1461 * Parameters:
1462 * handle: The window handle to destroy.
1463 */
1464 int dw_window_destroy(HWND handle)
1465 {
1466 if(!handle)
1467 return 0;
1468
1469 if(GTK_IS_WIDGET(handle))
1470 {
1471 GtkWidget *box, *handle2 = handle;
1472 GtkWidget *eventbox = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_eventbox");
1473
1474 /* Handle the invisible event box if it exists */
1475 if(eventbox && GTK_IS_WIDGET(eventbox))
1476 handle2 = eventbox;
1477
1478 /* Check if we are removing a widget from a box */
1479 if((box = gtk_widget_get_parent(handle2)) && GTK_IS_GRID(box))
1480 {
1481 /* Get the number of items in the box... */
1482 int boxcount = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(box), "_dw_boxcount"));
1483 int boxtype = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(box), "_dw_boxtype"));
1484 int z;
1485
1486 /* Figure out where in the grid this widget is and remove that row/column */
1487 if(boxtype == DW_VERT)
1488 {
1489 for(z=0;z<boxcount;z++)
1490 {
1491 if(gtk_grid_get_child_at(GTK_GRID(box), 0, z) == handle2)
1492 {
1493 gtk_grid_remove_row(GTK_GRID(box), z);
1494 break;
1495 }
1496 }
1497 }
1498 else
1499 {
1500 for(z=0;z<boxcount;z++)
1501 {
1502 if(gtk_grid_get_child_at(GTK_GRID(box), z, 0) == handle2)
1503 {
1504 gtk_grid_remove_column(GTK_GRID(box), z);
1505 break;
1506 }
1507 }
1508 }
1509
1510 if(boxcount > 0)
1511 {
1512 /* Decrease the count by 1 */
1513 boxcount--;
1514 g_object_set_data(G_OBJECT(box), "_dw_boxcount", GINT_TO_POINTER(boxcount));
1515 }
1516 }
1517 /* Finally destroy the widget, make sure it is still
1518 * a valid widget if it got removed from the grid.
1519 */
1520 if(GTK_IS_WIDGET(handle2))
1521 gtk_widget_destroy(handle2);
1522 }
1523 return 0;
1524 }
1525
1526 /* Causes entire window to be invalidated and redrawn.
1527 * Parameters:
1528 * handle: Toplevel window handle to be redrawn.
1529 */
1530 void dw_window_redraw(HWND handle)
1531 {
1532 }
1533
1534 /*
1535 * Changes a window's parent to newparent.
1536 * Parameters:
1537 * handle: The window handle to destroy.
1538 * newparent: The window's new parent window.
1539 */
1540 void dw_window_reparent(HWND handle, HWND newparent)
1541 {
1542 gdk_window_reparent(gtk_widget_get_window(GTK_WIDGET(handle)), newparent ? gtk_widget_get_window(GTK_WIDGET(newparent)) : gdk_get_default_root_window(), 0, 0);
1543 }
1544
1545 /*
1546 * Sets the default font used on text based widgets.
1547 * Parameters:
1548 * fontname: Font name in Dynamic Windows format.
1549 */
1550 void API dw_font_set_default(const char *fontname)
1551 {
1552 char *oldfont = _DWDefaultFont;
1553
1554 _DWDefaultFont = strdup(fontname);
1555
1556 if(oldfont)
1557 free(oldfont);
1558 }
1559
1560 /* Convert DW style font to CSS syntax (or Pango for older versions):
1561 * font: font-style font-variant font-weight font-size/line-height font-family
1562 */
1563 char *_convert_font(const char *font)
1564 {
1565 char *newfont = NULL;
1566
1567 if(font)
1568 {
1569 char *name = strchr(font, '.');
1570 #if GTK_CHECK_VERSION(3,20,0)
1571 char *Italic = strstr(font, " Italic");
1572 char *Bold = strstr(font, " Bold");
1573 #endif
1574
1575 /* Detect Dynamic Windows style font name...
1576 * Format: ##.Fontname
1577 * and convert to CSS or Pango syntax
1578 */
1579 if(name && (name++) && isdigit(*font))
1580 {
1581 int size = atoi(font);
1582 #if GTK_CHECK_VERSION(3,20,0)
1583 int len = (Italic ? (Bold ? (Italic > Bold ? (Bold - name) : (Italic - name)) : (Italic - name)) : (Bold ? (Bold - name) : strlen(name)));
1584 char *newname = alloca(len+1);
1585
1586 memset(newname, 0, len+1);
1587 strncpy(newname, name, len);
1588
1589 newfont = g_strdup_printf("%s normal %s %dpx \"%s\"", Italic ? "italic" : "normal",
1590 Bold ? "bold" : "normal", size, newname);
1591 #else
1592 newfont = g_strdup_printf("%s %d", name, size);
1593 #endif
1594 }
1595 }
1596 return newfont;
1597 }
1598
1599 /* Internal functions to convert to GTK3 style CSS */
1600 static void _dw_override_color(GtkWidget *widget, const char *element, GdkRGBA *color)
1601 {
1602 gchar *dataname = g_strdup_printf ("_dw_color_%s", element);
1603 GtkCssProvider *provider = g_object_get_data(G_OBJECT(widget), dataname);
1604 GtkStyleContext *scontext = gtk_widget_get_style_context(widget);
1605
1606 /* If we have an old context from a previous override remove it */
1607 if(provider)
1608 {
1609 gtk_style_context_remove_provider(scontext, GTK_STYLE_PROVIDER(provider));
1610 g_object_unref(provider);
1611 provider = NULL;
1612 }
1613
1614 /* If we have a new color, create a new provider and add it */
1615 if(color)
1616 {
1617 gchar *scolor = gdk_rgba_to_string(color);
1618 gchar *css = g_strdup_printf ("* { %s: %s; }", element, scolor);
1619
1620 provider = gtk_css_provider_new();
1621 g_free(scolor);
1622 gtk_css_provider_load_from_data(provider, css, -1, NULL);
1623 g_free(css);
1624 gtk_style_context_add_provider(scontext, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1625 }
1626 g_object_set_data(G_OBJECT(widget), dataname, (gpointer)provider);
1627 g_free(dataname);
1628 }
1629
1630 static void _dw_override_font(GtkWidget *widget, const char *font)
1631 {
1632 GtkCssProvider *provider = g_object_get_data(G_OBJECT(widget), "_dw_font");
1633 GtkStyleContext *scontext = gtk_widget_get_style_context(widget);
1634
1635 /* If we have an old context from a previous override remove it */
1636 if(provider)
1637 {
1638 gtk_style_context_remove_provider(scontext, GTK_STYLE_PROVIDER(provider));
1639 g_object_unref(provider);
1640 provider = NULL;
1641 }
1642
1643 /* If we have a new font, create a new provider and add it */
1644 if(font)
1645 {
1646 gchar *css = g_strdup_printf ("* { font: %s; }", font);
1647
1648 provider = gtk_css_provider_new();
1649 gtk_css_provider_load_from_data(provider, css, -1, NULL);
1650 g_free(css);
1651 gtk_style_context_add_provider(scontext, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1652 }
1653 g_object_set_data(G_OBJECT(widget), "_dw_font", (gpointer)provider);
1654 }
1655
1656 /*
1657 * Sets the font used by a specified window (widget) handle.
1658 * Parameters:
1659 * handle: The window (widget) handle.
1660 * fontname: Name and size of the font in the form "size.fontname"
1661 */
1662 int dw_window_set_font(HWND handle, const char *fontname)
1663 {
1664 GtkWidget *handle2 = handle;
1665 char *font = _convert_font(fontname);
1666 gpointer data;
1667
1668 if(GTK_IS_SCROLLED_WINDOW(handle))
1669 {
1670 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
1671 if(tmp)
1672 handle2 = tmp;
1673 }
1674 /* If it is a groupox we want to operate on the frame label */
1675 else if(GTK_IS_FRAME(handle))
1676 {
1677 GtkWidget *tmp = gtk_frame_get_label_widget(GTK_FRAME(handle));
1678 if(tmp)
1679 handle2 = tmp;
1680 }
1681 else if(GTK_IS_COMBO_BOX(handle) || GTK_IS_BUTTON(handle))
1682 {
1683 GtkWidget *tmp = gtk_bin_get_child(GTK_BIN(handle));
1684 if(tmp)
1685 handle2 = tmp;
1686 }
1687
1688 /* Free old font name if one is allocated */
1689 data = g_object_get_data(G_OBJECT(handle2), "_dw_fontname");
1690 g_object_set_data(G_OBJECT(handle2), "_dw_fontname", (gpointer)font);
1691 if(data)
1692 free(data);
1693
1694 _dw_override_font(handle2, font);
1695
1696 return TRUE;
1697 }
1698
1699 /* Allows the user to choose a font using the system's font chooser dialog.
1700 * Parameters:
1701 * currfont: current font
1702 * Returns:
1703 * A malloced buffer with the selected font or NULL on error.
1704 */
1705 char * API dw_font_choose(const char *currfont)
1706 {
1707 GtkFontChooser *fd;
1708 char *font = currfont ? strdup(currfont) : NULL;
1709 char *name = font ? strchr(font, '.') : NULL;
1710 char *retfont = NULL;
1711
1712 /* Detect Dynamic Windows style font name...
1713 * Format: ##.Fontname
1714 * and convert to a Pango name
1715 */
1716 if(name && isdigit(*font))
1717 {
1718 int size = atoi(font);
1719 *name = 0;
1720 name++;
1721 sprintf(font, "%s %d", name, size);
1722 }
1723
1724 fd = (GtkFontChooser *)gtk_font_chooser_dialog_new("Choose font", NULL);
1725 if(font)
1726 {
1727 gtk_font_chooser_set_font(fd, font);
1728 free(font);
1729 }
1730
1731 gtk_widget_show(GTK_WIDGET(fd));
1732
1733 if(gtk_dialog_run(GTK_DIALOG(fd)) == GTK_RESPONSE_OK)
1734 {
1735 char *fontname = gtk_font_chooser_get_font(fd);
1736 if(fontname && (retfont = strdup(fontname)))
1737 {
1738 int len = strlen(fontname);
1739 /* Convert to Dynamic Windows format if we can... */
1740 if(len > 0 && isdigit(fontname[len-1]))
1741 {
1742 int size, x=len-1;
1743
1744 while(x > 0 && fontname[x] != ' ')
1745 {
1746 x--;
1747 }
1748 size = atoi(&fontname[x]);
1749 /* If we were able to find a valid size... */
1750 if(size > 0)
1751 {
1752 /* Null terminate after the name...
1753 * and create the Dynamic Windows style font.
1754 */
1755 fontname[x] = 0;
1756 snprintf(retfont, len+1, "%d.%s", size, fontname);
1757 }
1758 }
1759 g_free(fontname);
1760 }
1761 }
1762 gtk_widget_destroy(GTK_WIDGET(fd));
1763 return retfont;
1764 }
1765
1766 /*
1767 * Gets the font used by a specified window (widget) handle.
1768 * Parameters:
1769 * handle: The window (widget) handle.
1770 */
1771 char *dw_window_get_font(HWND handle)
1772 {
1773 PangoFontDescription *pfont;
1774 PangoContext *pcontext;
1775 GtkWidget *handle2 = handle;
1776 char *font;
1777 char *retfont=NULL;
1778
1779 if(GTK_IS_SCROLLED_WINDOW(handle))
1780 {
1781 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
1782 if(tmp)
1783 handle2 = tmp;
1784 }
1785 /* If it is a groupox we want to operate on the frame label */
1786 else if(GTK_IS_FRAME(handle))
1787 {
1788 GtkWidget *tmp = gtk_frame_get_label_widget(GTK_FRAME(handle));
1789 if(tmp)
1790 handle2 = tmp;
1791 }
1792
1793 pcontext = gtk_widget_get_pango_context( handle2 );
1794 if ( pcontext )
1795 {
1796 pfont = pango_context_get_font_description( pcontext );
1797 if ( pfont )
1798 {
1799 int len, x;
1800
1801 font = pango_font_description_to_string( pfont );
1802 retfont = strdup(font);
1803 len = strlen(font);
1804 /* Convert to Dynamic Windows format if we can... */
1805 if(len > 0 && isdigit(font[len-1]))
1806 {
1807 int size;
1808
1809 x=len-1;
1810 while(x > 0 && font[x] != ' ')
1811 {
1812 x--;
1813 }
1814 size = atoi(&font[x]);
1815 /* If we were able to find a valid size... */
1816 if(size > 0)
1817 {
1818 /* Null terminate after the name...
1819 * and create the Dynamic Windows style font.
1820 */
1821 font[x] = 0;
1822 snprintf(retfont, len+1, "%d.%s", size, font);
1823 }
1824 }
1825 g_free( font );
1826 }
1827 }
1828 return retfont;
1829 }
1830
1831 void _free_gdk_colors(HWND handle)
1832 {
1833 GdkRGBA *old = (GdkRGBA *)g_object_get_data(G_OBJECT(handle), "_dw_foregdk");
1834
1835 if(old)
1836 free(old);
1837
1838 old = (GdkRGBA *)g_object_get_data(G_OBJECT(handle), "_dw_backgdk");
1839
1840 if(old)
1841 free(old);
1842 }
1843
1844 /* Free old color pointers and allocate new ones */
1845 static void _save_gdk_colors(HWND handle, GdkRGBA fore, GdkRGBA back)
1846 {
1847 GdkRGBA *foregdk = malloc(sizeof(GdkRGBA));
1848 GdkRGBA *backgdk = malloc(sizeof(GdkRGBA));
1849
1850 _free_gdk_colors(handle);
1851
1852 *foregdk = fore;
1853 *backgdk = back;
1854
1855 g_object_set_data(G_OBJECT(handle), "_dw_foregdk", (gpointer)foregdk);
1856 g_object_set_data(G_OBJECT(handle), "_dw_backgdk", (gpointer)backgdk);
1857 }
1858
1859 static int _set_color(HWND handle, unsigned long fore, unsigned long back)
1860 {
1861 /* Remember that each color component in X11 use 16 bit no matter
1862 * what the destination display supports. (and thus GDK)
1863 */
1864 GdkRGBA forecolor = {0}, backcolor = {0};
1865
1866 if(fore & DW_RGB_COLOR)
1867 {
1868 forecolor.alpha = 1.0;
1869 forecolor.red = (gdouble)DW_RED_VALUE(fore) / 255.0;
1870 forecolor.green = (gdouble)DW_GREEN_VALUE(fore) / 255.0;
1871 forecolor.blue = (gdouble)DW_BLUE_VALUE(fore) / 255.0;
1872 }
1873 else if(fore != DW_CLR_DEFAULT)
1874 forecolor = _colors[fore];
1875
1876 _dw_override_color(handle, "color", fore != DW_CLR_DEFAULT ? &forecolor : NULL);
1877
1878 if(back & DW_RGB_COLOR)
1879 {
1880 backcolor.alpha = 1.0;
1881 backcolor.red = (gdouble)DW_RED_VALUE(back) / 255.0;
1882 backcolor.green = (gdouble)DW_GREEN_VALUE(back) / 255.0;
1883 backcolor.blue = (gdouble)DW_BLUE_VALUE(back) / 255.0;
1884 }
1885 else if(back != DW_CLR_DEFAULT)
1886 backcolor = _colors[back];
1887
1888 _dw_override_color(handle, "background-color", back != DW_CLR_DEFAULT ? &backcolor : NULL);
1889
1890 _save_gdk_colors(handle, forecolor, backcolor);
1891
1892 return TRUE;
1893 }
1894 /*
1895 * Sets the colors used by a specified window (widget) handle.
1896 * Parameters:
1897 * handle: The window (widget) handle.
1898 * fore: Foreground color in RGB format.
1899 * back: Background color in RGB format.
1900 */
1901 int dw_window_set_color(HWND handle, unsigned long fore, unsigned long back)
1902 {
1903 GtkWidget *handle2 = handle;
1904
1905 if(GTK_IS_SCROLLED_WINDOW(handle) || GTK_IS_BOX(handle))
1906 {
1907 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
1908 if(tmp)
1909 handle2 = tmp;
1910 }
1911 else if(GTK_IS_GRID(handle))
1912 {
1913 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_eventbox");
1914 if(tmp)
1915 {
1916 handle2 = tmp;
1917 fore = DW_CLR_DEFAULT;
1918 }
1919 }
1920
1921 _set_color(handle2, fore, back);
1922
1923 return TRUE;
1924 }
1925
1926 /*
1927 * Sets the font used by a specified window (widget) handle.
1928 * Parameters:
1929 * handle: The window (widget) handle.
1930 * border: Size of the window border in pixels.
1931 */
1932 int dw_window_set_border(HWND handle, int border)
1933 {
1934 /* TODO */
1935 return 0;
1936 }
1937
1938 #if GTK_CHECK_VERSION(3,20,0)
1939 static GdkSeat *_dw_grab_seat = NULL;
1940 #else
1941 static GdkDeviceManager *_dw_grab_manager = NULL;
1942 #endif
1943
1944 /*
1945 * Captures the mouse input to this window.
1946 * Parameters:
1947 * handle: Handle to receive mouse input.
1948 */
1949 void dw_window_capture(HWND handle)
1950 {
1951 _dw_grab_seat = gdk_display_get_default_seat(gtk_widget_get_display(handle));
1952 gdk_seat_grab (_dw_grab_seat,
1953 gtk_widget_get_window(handle),
1954 GDK_SEAT_CAPABILITY_ALL_POINTING,
1955 FALSE, NULL, NULL, NULL, NULL);
1956 }
1957
1958 /*
1959 * Changes the appearance of the mouse pointer.
1960 * Parameters:
1961 * handle: Handle to widget for which to change.
1962 * cursortype: ID of the pointer you want.
1963 */
1964 void dw_window_set_pointer(HWND handle, int pointertype)
1965 {
1966 GdkCursor *cursor;
1967
1968 if(pointertype > 65535)
1969 {
1970 GdkPixbuf *pixbuf = _find_pixbuf(GINT_TO_POINTER(pointertype), NULL, NULL);
1971 cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf, 8, 8);
1972 }
1973 else if(!pointertype)
1974 cursor = NULL;
1975 else
1976 cursor = gdk_cursor_new_for_display(gdk_display_get_default(), pointertype);
1977 if(handle && gtk_widget_get_window(handle))
1978 gdk_window_set_cursor(gtk_widget_get_window(handle), cursor);
1979 if(cursor)
1980 g_object_unref(cursor);
1981 }
1982
1983 /*
1984 * Releases previous mouse capture.
1985 */
1986 void dw_window_release(void)
1987 {
1988 if(_dw_grab_seat)
1989 gdk_seat_ungrab(_dw_grab_seat);
1990 _dw_grab_seat = NULL;
1991 }
1992
1993 /*
1994 * Create a new Window Frame.
1995 * Parameters:
1996 * owner: The Owner's window handle or HWND_DESKTOP.
1997 * title: The Window title.
1998 * flStyle: Style flags, see the PM reference.
1999 */
2000 HWND dw_window_new(HWND hwndOwner, const char *title, unsigned long flStyle)
2001 {
2002 GtkWidget *tmp;
2003 int flags = 0;
2004
2005 {
2006 GtkWidget *box = dw_box_new(DW_VERT, 0);
2007 GtkWidget *grid = gtk_grid_new();
2008
2009 gtk_widget_show_all(grid);
2010
2011 last_window = tmp = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2012
2013 gtk_window_set_title(GTK_WINDOW(tmp), title);
2014 gtk_window_set_resizable(GTK_WINDOW(tmp), (flStyle & DW_FCF_SIZEBORDER) ? TRUE : FALSE);
2015
2016 gtk_widget_realize(tmp);
2017
2018 if(flStyle & DW_FCF_TITLEBAR)
2019 flags |= GDK_DECOR_TITLE;
2020
2021 if(flStyle & DW_FCF_MINMAX)
2022 flags |= GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE;
2023
2024 if(flStyle & DW_FCF_SIZEBORDER)
2025 flags |= GDK_DECOR_RESIZEH | GDK_DECOR_BORDER;
2026
2027 if(flStyle & (DW_FCF_BORDER | DW_FCF_DLGBORDER))
2028 flags |= GDK_DECOR_BORDER;
2029
2030 if(flStyle & DW_FCF_FULLSCREEN)
2031 gtk_window_fullscreen(GTK_WINDOW(tmp));
2032 else
2033 {
2034 if(flStyle & DW_FCF_MAXIMIZE)
2035 gtk_window_maximize(GTK_WINDOW(tmp));
2036
2037 if(flStyle & DW_FCF_MINIMIZE)
2038 gtk_window_iconify(GTK_WINDOW(tmp));
2039 }
2040
2041 /* Either the CLOSEBUTTON or SYSMENU flags should make it deletable */
2042 gtk_window_set_deletable(GTK_WINDOW(tmp), (flStyle & (DW_FCF_CLOSEBUTTON | DW_FCF_SYSMENU)) ? TRUE : FALSE);
2043
2044 gdk_window_set_decorations(gtk_widget_get_window(tmp), flags);
2045 if(!flags)
2046 gtk_window_set_decorated(GTK_WINDOW(tmp), FALSE);
2047
2048 if(hwndOwner)
2049 gdk_window_reparent(gtk_widget_get_window(GTK_WIDGET(tmp)), gtk_widget_get_window(GTK_WIDGET(hwndOwner)), 0, 0);
2050
2051 if(flStyle & DW_FCF_SIZEBORDER)
2052 g_object_set_data(G_OBJECT(tmp), "_dw_size", GINT_TO_POINTER(1));
2053
2054 gtk_grid_attach(GTK_GRID(grid), box, 0, 1, 1, 1);
2055 gtk_container_add(GTK_CONTAINER(tmp), grid);
2056 g_object_set_data(G_OBJECT(tmp), "_dw_boxhandle", (gpointer)box);
2057 g_object_set_data(G_OBJECT(tmp), "_dw_grid", (gpointer)grid);
2058 gtk_widget_add_events(GTK_WIDGET(tmp), GDK_PROPERTY_CHANGE_MASK);
2059 }
2060 g_object_set_data(G_OBJECT(tmp), "_dw_style", GINT_TO_POINTER(flStyle));
2061 return tmp;
2062 }
2063
2064 /*
2065 * Create a new Box to be packed.
2066 * Parameters:
2067 * type: Either DW_VERT (vertical) or DW_HORZ (horizontal).
2068 * pad: Number of pixels to pad around the box.
2069 */
2070 HWND dw_box_new(int type, int pad)
2071 {
2072 GtkWidget *tmp, *eventbox;
2073
2074 tmp = gtk_grid_new();
2075 eventbox = gtk_event_box_new();
2076
2077 gtk_widget_show(eventbox);
2078 g_object_set_data(G_OBJECT(tmp), "_dw_eventbox", (gpointer)eventbox);
2079 g_object_set_data(G_OBJECT(tmp), "_dw_boxtype", GINT_TO_POINTER(type));
2080 g_object_set_data(G_OBJECT(tmp), "_dw_boxpad", GINT_TO_POINTER(pad));
2081 gtk_widget_show(tmp);
2082 return tmp;
2083 }
2084
2085 /*
2086 * Create a new scrollable Box to be packed.
2087 * Parameters:
2088 * type: Either DW_VERT (vertical) or DW_HORZ (horizontal).
2089 * pad: Number of pixels to pad around the box.
2090 */
2091 HWND dw_scrollbox_new( int type, int pad )
2092 {
2093 GtkWidget *tmp, *box, *eventbox;
2094
2095 tmp = gtk_scrolled_window_new(NULL, NULL);
2096 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (tmp), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2097
2098 box = gtk_grid_new();
2099 eventbox = gtk_event_box_new();
2100
2101 gtk_widget_show(eventbox);
2102 g_object_set_data(G_OBJECT(box), "_dw_eventbox", (gpointer)eventbox);
2103 g_object_set_data(G_OBJECT(box), "_dw_boxtype", GINT_TO_POINTER(type));
2104 g_object_set_data(G_OBJECT(box), "_dw_boxpad", GINT_TO_POINTER(pad));
2105 g_object_set_data(G_OBJECT(tmp), "_dw_boxhandle", (gpointer)box);
2106
2107 gtk_container_add(GTK_CONTAINER(tmp), box);
2108 g_object_set_data(G_OBJECT(tmp), "_dw_user", box);
2109 gtk_widget_show(box);
2110 gtk_widget_show(tmp);
2111
2112 return tmp;
2113 }
2114
2115 /*
2116 * Returns the position of the scrollbar in the scrollbox
2117 * Parameters:
2118 * handle: Handle to the scrollbox to be queried.
2119 * orient: The vertical or horizontal scrollbar.
2120 */
2121 int dw_scrollbox_get_pos(HWND handle, int orient)
2122 {
2123 int val = -1;
2124 GtkAdjustment *adjustment;
2125
2126 if (!handle)
2127 return -1;
2128
2129 if ( orient == DW_HORZ )
2130 adjustment = gtk_scrolled_window_get_hadjustment( GTK_SCROLLED_WINDOW(handle) );
2131 else
2132 adjustment = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW(handle) );
2133 if (adjustment)
2134 val = _round_value(gtk_adjustment_get_value(adjustment));
2135 return val;
2136 }
2137
2138 /*
2139 * Gets the range for the scrollbar in the scrollbox.
2140 * Parameters:
2141 * handle: Handle to the scrollbox to be queried.
2142 * orient: The vertical or horizontal scrollbar.
2143 */
2144 int API dw_scrollbox_get_range(HWND handle, int orient)
2145 {
2146 int range = -1;
2147 GtkAdjustment *adjustment;
2148
2149 if (!handle)
2150 return -1;
2151
2152 if ( orient == DW_HORZ )
2153 adjustment = gtk_scrolled_window_get_hadjustment( GTK_SCROLLED_WINDOW(handle) );
2154 else
2155 adjustment = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW(handle) );
2156 if (adjustment)
2157 {
2158 range = _round_value(gtk_adjustment_get_upper(adjustment));
2159 }
2160 return range;
2161 }
2162
2163 /*
2164 * Create a new Group Box to be packed.
2165 * Parameters:
2166 * type: Either DW_VERT (vertical) or DW_HORZ (horizontal).
2167 * pad: Number of pixels to pad around the box.
2168 * title: Text to be displayined in the group outline.
2169 */
2170 HWND dw_groupbox_new(int type, int pad, const char *title)
2171 {
2172 GtkWidget *tmp, *frame;
2173
2174 frame = gtk_frame_new(NULL);
2175 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
2176 gtk_frame_set_label(GTK_FRAME(frame), title && *title ? title : NULL);
2177
2178 tmp = gtk_grid_new();
2179 gtk_container_set_border_width(GTK_CONTAINER(tmp), pad);
2180 g_object_set_data(G_OBJECT(tmp), "_dw_boxtype", GINT_TO_POINTER(type));
2181 g_object_set_data(G_OBJECT(tmp), "_dw_boxpad", GINT_TO_POINTER(pad));
2182 g_object_set_data(G_OBJECT(frame), "_dw_boxhandle", (gpointer)tmp);
2183 gtk_container_add(GTK_CONTAINER(frame), tmp);
2184 gtk_widget_show(tmp);
2185 gtk_widget_show(frame);
2186 if(_DWDefaultFont)
2187 dw_window_set_font(frame, _DWDefaultFont);
2188 return frame;
2189 }
2190
2191 /*
2192 * Create a bitmap object to be packed.
2193 * Parameters:
2194 * id: An ID to be used with dw_window_from_id() or 0L.
2195 */
2196 HWND dw_bitmap_new(unsigned long id)
2197 {
2198 GtkWidget *tmp;
2199
2200 tmp = gtk_image_new();
2201 gtk_widget_show(tmp);
2202 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2203 return tmp;
2204 }
2205
2206 /*
2207 * Create a notebook object to be packed.
2208 * Parameters:
2209 * id: An ID to be used for getting the resource from the
2210 * resource file.
2211 */
2212 HWND dw_notebook_new(unsigned long id, int top)
2213 {
2214 GtkWidget *tmp, **pagearray = calloc(sizeof(GtkWidget *), 256);
2215
2216 tmp = gtk_notebook_new();
2217 if(top)
2218 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tmp), GTK_POS_TOP);
2219 else
2220 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tmp), GTK_POS_BOTTOM);
2221 gtk_notebook_set_scrollable(GTK_NOTEBOOK(tmp), TRUE);
2222 gtk_widget_show(tmp);
2223 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2224 g_object_set_data(G_OBJECT(tmp), "_dw_pagearray", (gpointer)pagearray);
2225 return tmp;
2226 }
2227
2228 /*
2229 * Create a menu object to be popped up.
2230 * Parameters:
2231 * id: An ID to be used for getting the resource from the
2232 * resource file.
2233 */
2234 HMENUI dw_menu_new(unsigned long id)
2235 {
2236 GtkAccelGroup *accel_group;
2237 HMENUI tmp;
2238
2239 tmp = gtk_menu_new();
2240 gtk_widget_show(tmp);
2241 accel_group = gtk_accel_group_new();
2242 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2243 g_object_set_data(G_OBJECT(tmp), "_dw_accel", (gpointer)accel_group);
2244 return tmp;
2245 }
2246
2247 /*
2248 * Create a menubar on a window.
2249 * Parameters:
2250 * location: Handle of a window frame to be attached to.
2251 * If there is no box already packed into the "location", the menu will not appear
2252 * so tell the user.
2253 */
2254 HMENUI dw_menubar_new(HWND location)
2255 {
2256 GtkAccelGroup *accel_group;
2257 GtkWidget *box;
2258 HMENUI tmp = 0;
2259
2260 if(GTK_IS_WINDOW(location) &&
2261 (box = (GtkWidget *)g_object_get_data(G_OBJECT(location), "_dw_grid")))
2262 {
2263 /* If there is an existing menu bar, remove it */
2264 GtkWidget *oldmenu = (GtkWidget *)g_object_get_data(G_OBJECT(location), "_dw_menubar");
2265 if(oldmenu)
2266 gtk_widget_destroy(oldmenu);
2267 /* Create a new menu bar */
2268 tmp = gtk_menu_bar_new();
2269 gtk_widget_show(tmp);
2270 accel_group = gtk_accel_group_new();
2271 g_object_set_data(G_OBJECT(tmp), "_dw_accel", (gpointer)accel_group);
2272 /* Save pointers to each other */
2273 g_object_set_data(G_OBJECT(location), "_dw_menubar", (gpointer)tmp);
2274 g_object_set_data(G_OBJECT(tmp), "_dw_window", (gpointer)location);
2275 gtk_grid_attach(GTK_GRID(box), tmp, 0, 0, 1, 1);
2276 }
2277 return tmp;
2278 }
2279
2280 /*
2281 * Destroys a menu created with dw_menubar_new or dw_menu_new.
2282 * Parameters:
2283 * menu: Handle of a menu.
2284 */
2285 void dw_menu_destroy(HMENUI *menu)
2286 {
2287 if(menu && *menu)
2288 {
2289 GtkWidget *window;
2290
2291 /* If it is a menu bar, try to delete the reference to it */
2292 if(GTK_IS_MENU_BAR(*menu) &&
2293 (window = (GtkWidget *)g_object_get_data(G_OBJECT(*menu), "_dw_window")))
2294 g_object_set_data(G_OBJECT(window), "_dw_menubar", NULL);
2295 /* Actually destroy the menu */
2296 gtk_widget_destroy(*menu);
2297 *menu = NULL;
2298 }
2299 }
2300
2301 char _removetilde(char *dest, const char *src)
2302 {
2303 int z, cur=0;
2304 char accel = '\0';
2305
2306 for(z=0;z<strlen(src);z++)
2307 {
2308 if(src[z] != '~')
2309 {
2310 dest[cur] = src[z];
2311 cur++;
2312 }
2313 else
2314 {
2315 dest[cur] = '_';
2316 accel = src[z+1];
2317 cur++;
2318 }
2319 }
2320 dest[cur] = 0;
2321 return accel;
2322 }
2323
2324 /*
2325 * Adds a menuitem or submenu to an existing menu.
2326 * Parameters:
2327 * menu: The handle to the existing menu.
2328 * title: The title text on the menu item to be added.
2329 * id: An ID to be used for message passing.
2330 * flags: Extended attributes to set on the menu.
2331 * end: If TRUE memu is positioned at the end of the menu.
2332 * check: If TRUE menu is "check"able.
2333 * submenu: Handle to an existing menu to be a submenu or NULL.
2334 */
2335 HWND dw_menu_append_item(HMENUI menu, const char *title, unsigned long id, unsigned long flags, int end, int check, HMENUI submenu)
2336 {
2337 GtkWidget *tmphandle;
2338 char accel, *tempbuf = malloc(strlen(title)+1);
2339 int submenucount;
2340 GtkAccelGroup *accel_group;
2341
2342 if (!menu)
2343 {
2344 free(tempbuf);
2345 return NULL;
2346 }
2347
2348 accel = _removetilde(tempbuf, title);
2349
2350 accel_group = (GtkAccelGroup *)g_object_get_data(G_OBJECT(menu), "_dw_accel");
2351 submenucount = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "_dw_submenucount"));
2352
2353 if (strlen(tempbuf) == 0)
2354 tmphandle=gtk_menu_item_new();
2355 else
2356 {
2357 char numbuf[25] = {0};
2358
2359 if (check)
2360 {
2361 tmphandle = gtk_check_menu_item_new_with_label(tempbuf);
2362 if (accel && accel_group)
2363 {
2364 gtk_label_set_use_underline(GTK_LABEL(gtk_bin_get_child(GTK_BIN(tmphandle))), TRUE);
2365 #if 0 /* TODO: This isn't working right */
2366 gtk_widget_add_accelerator(tmphandle, "activate", accel_group, tmp_key, GDK_MOD1_MASK, 0);
2367 #endif
2368 }
2369 snprintf(numbuf, 24, "%lu", id);
2370 g_object_set_data(G_OBJECT(menu), numbuf, (gpointer)tmphandle);
2371 }
2372 else
2373 {
2374 tmphandle=gtk_menu_item_new_with_label(tempbuf);
2375 if (accel && accel_group)
2376 {
2377 gtk_label_set_use_underline(GTK_LABEL(gtk_bin_get_child(GTK_BIN(tmphandle))), TRUE);
2378 #if 0 /* TODO: This isn't working right */
2379 gtk_widget_add_accelerator(tmphandle, "activate", accel_group, tmp_key, GDK_MOD1_MASK, 0);
2380 #endif
2381 }
2382 snprintf(numbuf, 24, "%lu", id);
2383 g_object_set_data(G_OBJECT(menu), numbuf, (gpointer)tmphandle);
2384 }
2385 }
2386
2387 gtk_widget_show(tmphandle);
2388
2389 if (submenu)
2390 {
2391 char tempbuf[101] = {0};
2392
2393 snprintf(tempbuf, 100, "_dw_submenu%d", submenucount);
2394 submenucount++;
2395 gtk_menu_item_set_submenu(GTK_MENU_ITEM(tmphandle), submenu);
2396 g_object_set_data(G_OBJECT(menu), tempbuf, (gpointer)submenu);
2397 g_object_set_data(G_OBJECT(menu), "_dw_submenucount", GINT_TO_POINTER(submenucount));
2398 }
2399
2400 if (GTK_IS_MENU_BAR(menu))
2401 gtk_menu_shell_append(GTK_MENU_SHELL(menu), tmphandle);
2402 else
2403 gtk_menu_shell_append(GTK_MENU_SHELL(menu), tmphandle);
2404
2405 g_object_set_data(G_OBJECT(tmphandle), "_dw_id", GINT_TO_POINTER(id));
2406 free(tempbuf);
2407 /*
2408 * Set flags
2409 */
2410 if ( check && (flags & DW_MIS_CHECKED) )
2411 {
2412 _dw_ignore_click = 1;
2413 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(tmphandle), 1);
2414 _dw_ignore_click = 0;
2415 }
2416
2417 if ( flags & DW_MIS_DISABLED )
2418 gtk_widget_set_sensitive( tmphandle, FALSE );
2419
2420 return tmphandle;
2421 }
2422
2423 GtkWidget *_find_submenu_id(GtkWidget *start, const char *name)
2424 {
2425 GtkWidget *tmp;
2426 int z, submenucount = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(start), "_dw_submenucount"));
2427
2428 if((tmp = g_object_get_data(G_OBJECT(start), name)))
2429 return tmp;
2430
2431 for(z=0;z<submenucount;z++)
2432 {
2433 char tempbuf[101] = {0};
2434 GtkWidget *submenu, *menuitem;
2435
2436 snprintf(tempbuf, 100, "_dw_submenu%d", z);
2437
2438 if((submenu = g_object_get_data(G_OBJECT(start), tempbuf)))
2439 {
2440 if((menuitem = _find_submenu_id(submenu, name)))
2441 return menuitem;
2442 }
2443 }
2444 return NULL;
2445 }
2446
2447 /*
2448 * Sets the state of a menu item check.
2449 * Parameters:
2450 * menu: The handle the the existing menu.
2451 * id: Menuitem id.
2452 * check: TRUE for checked FALSE for not checked.
2453 * deprecated: use dw_menu_item_set_state()
2454 */
2455 void dw_menu_item_set_check(HMENUI menu, unsigned long id, int check)
2456 {
2457 char numbuf[25] = {0};
2458 GtkWidget *tmphandle;
2459
2460 if(!menu)
2461 return;
2462
2463 snprintf(numbuf, 24, "%lu", id);
2464 tmphandle = _find_submenu_id(menu, numbuf);
2465
2466 if(tmphandle)
2467 {
2468 _dw_ignore_click = 1;
2469 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(tmphandle)) != check)
2470 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(tmphandle), check);
2471 _dw_ignore_click = 0;
2472 }
2473 }
2474
2475 /*
2476 * Sets the state of a menu item.
2477 * Parameters:
2478 * menu: The handle the the existing menu.
2479 * id: Menuitem id.
2480 * state: TRUE for checked FALSE for not checked.
2481 */
2482 void dw_menu_item_set_state(HMENUI menu, unsigned long id, unsigned long state)
2483 {
2484 char numbuf[25] = {0};
2485 GtkWidget *tmphandle;
2486 int check;
2487
2488 if(!menu)
2489 return;
2490
2491 snprintf(numbuf, 24, "%lu", id);
2492 tmphandle = _find_submenu_id(menu, numbuf);
2493
2494 if ( (state & DW_MIS_CHECKED) || (state & DW_MIS_UNCHECKED) )
2495 {
2496 if ( state & DW_MIS_CHECKED )
2497 check = 1;
2498 else
2499 check = 0;
2500
2501 if (tmphandle)
2502 {
2503 _dw_ignore_click = 1;
2504 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(tmphandle)) != check)
2505 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(tmphandle), check);
2506 _dw_ignore_click = 0;
2507 }
2508 }
2509 if ( (state & DW_MIS_ENABLED) || (state & DW_MIS_DISABLED) )
2510 {
2511 if (tmphandle )
2512 {
2513 _dw_ignore_click = 1;
2514 if ( state & DW_MIS_ENABLED )
2515 gtk_widget_set_sensitive( tmphandle, TRUE );
2516 else
2517 gtk_widget_set_sensitive( tmphandle, FALSE );
2518 _dw_ignore_click = 0;
2519 }
2520 }
2521 }
2522
2523 /*
2524 * Deletes the menu item specified.
2525 * Parameters:
2526 * menu: The handle to the menu in which the item was appended.
2527 * id: Menuitem id.
2528 * Returns:
2529 * DW_ERROR_NONE (0) on success or DW_ERROR_UNKNOWN on failure.
2530 */
2531 int API dw_menu_delete_item(HMENUI menu, unsigned long id)
2532 {
2533 char numbuf[25] = {0};
2534 GtkWidget *tmphandle;
2535 int ret = DW_ERROR_UNKNOWN;
2536
2537 if(!menu)
2538 return ret;
2539
2540 snprintf(numbuf, 24, "%lu", id);
2541 tmphandle = _find_submenu_id(menu, numbuf);
2542
2543 if(tmphandle)
2544 {
2545 gtk_widget_destroy(tmphandle);
2546 g_object_set_data(G_OBJECT(menu), numbuf, NULL);
2547 ret = DW_ERROR_NONE;
2548 }
2549 return ret;
2550 }
2551
2552 /*
2553 * Pops up a context menu at given x and y coordinates.
2554 * Parameters:
2555 * menu: The handle the the existing menu.
2556 * parent: Handle to the window initiating the popup.
2557 * x: X coordinate.
2558 * y: Y coordinate.
2559 */
2560 void dw_menu_popup(HMENUI *menu, HWND parent, int x, int y)
2561 {
2562 if(!menu || !*menu)
2563 return;
2564
2565 popup = parent;
2566
2567 gtk_menu_popup_at_pointer(GTK_MENU(*menu), NULL);
2568 *menu = NULL;
2569 }
2570
2571
2572 /*
2573 * Returns the current X and Y coordinates of the mouse pointer.
2574 * Parameters:
2575 * x: Pointer to variable to store X coordinate.
2576 * y: Pointer to variable to store Y coordinate.
2577 */
2578 void dw_pointer_query_pos(long *x, long *y)
2579 {
2580 GdkModifierType state = 0;
2581 int gx, gy;
2582 GdkDisplay *display;
2583 GdkDevice *device;
2584 GdkSeat *seat;
2585
2586 #ifdef GDK_WINDOWING_X11
2587 display = gdk_display_get_default();
2588 seat = gdk_display_get_default_seat(display);
2589 device = gdk_seat_get_pointer(seat);
2590 gdk_window_get_device_position(gdk_x11_window_lookup_for_display(display, GDK_ROOT_WINDOW()),
2591 device, &gx, &gy, &state);
2592 #endif
2593 if(x)
2594 *x = gx;
2595 if(y)
2596 *y = gy;
2597 }
2598
2599 /*
2600 * Sets the X and Y coordinates of the mouse pointer.
2601 * Parameters:
2602 * x: X coordinate.
2603 * y: Y coordinate.
2604 */
2605 void dw_pointer_set_pos(long x, long y)
2606 {
2607 GdkDisplay *display;
2608 GdkDevice *device;
2609 GdkSeat *seat;
2610
2611 #ifdef GDK_WINDOWING_X11
2612 display = gdk_display_get_default();
2613 seat = gdk_display_get_default_seat(display);
2614 device = gdk_seat_get_pointer(seat);
2615 gdk_device_warp(device, gdk_screen_get_default(), x, y);
2616 #endif
2617 }
2618
2619 #define _DW_TREE_CONTAINER 1
2620 #define _DW_TREE_TREE 2
2621 #define _DW_TREE_LISTBOX 3
2622
2623 GtkWidget *_tree_create(unsigned long id)
2624 {
2625 GtkWidget *tmp;
2626
2627 tmp = gtk_scrolled_window_new(NULL, NULL);
2628 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (tmp),
2629 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2630
2631 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2632 gtk_widget_show(tmp);
2633 return tmp;
2634 }
2635
2636 GtkWidget *_tree_setup(GtkWidget *tmp, GtkTreeModel *store)
2637 {
2638 GtkWidget *tree = gtk_tree_view_new_with_model(store);
2639 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(tree), FALSE);
2640 #if GTK_CHECK_VERSION(3,8,0)
2641 gtk_container_add(GTK_CONTAINER(tmp), tree);
2642 #else
2643 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tmp), tree);
2644 #endif
2645 g_object_set_data(G_OBJECT(tmp), "_dw_user", (gpointer)tree);
2646 return tree;
2647 }
2648
2649 /*
2650 * Create a container object to be packed.
2651 * Parameters:
2652 * id: An ID to be used for getting the resource from the
2653 * resource file.
2654 */
2655 HWND dw_container_new(unsigned long id, int multi)
2656 {
2657 GtkWidget *tmp;
2658
2659 if(!(tmp = _tree_create(id)))
2660 return 0;
2661 g_object_set_data(G_OBJECT(tmp), "_dw_tree_type", GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER));
2662 g_object_set_data(G_OBJECT(tmp), "_dw_multi_sel", GINT_TO_POINTER(multi));
2663 return tmp;
2664 }
2665
2666 /*
2667 * Create a tree object to be packed.
2668 * Parameters:
2669 * id: An ID to be used for getting the resource from the
2670 * resource file.
2671 */
2672 HWND dw_tree_new(ULONG id)
2673 {
2674 GtkWidget *tmp, *tree;
2675 GtkTreeStore *store;
2676 GtkTreeViewColumn *col;
2677 GtkCellRenderer *rend;
2678 GtkTreeSelection *sel;
2679
2680 if(!(tmp = _tree_create(id)))
2681 return 0;
2682 store = gtk_tree_store_new(4, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_POINTER, G_TYPE_POINTER);
2683 tree = _tree_setup(tmp, GTK_TREE_MODEL(store));
2684 g_object_set_data(G_OBJECT(tmp), "_dw_tree_type", GINT_TO_POINTER(_DW_TREE_TYPE_TREE));
2685 g_object_set_data(G_OBJECT(tree), "_dw_tree_type", GINT_TO_POINTER(_DW_TREE_TYPE_TREE));
2686 col = gtk_tree_view_column_new();
2687
2688 rend = gtk_cell_renderer_pixbuf_new();
2689 gtk_tree_view_column_pack_start(col, rend, FALSE);
2690 gtk_tree_view_column_add_attribute(col, rend, "pixbuf", 1);
2691 rend = gtk_cell_renderer_text_new();
2692 gtk_tree_view_column_pack_start(col, rend, TRUE);
2693 gtk_tree_view_column_add_attribute(col, rend, "text", 0);
2694
2695 gtk_tree_view_append_column(GTK_TREE_VIEW (tree), col);
2696 gtk_tree_view_set_expander_column(GTK_TREE_VIEW(tree), col);
2697 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE);
2698
2699 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
2700 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
2701 gtk_widget_show(tree);
2702
2703 if(_DWDefaultFont)
2704 dw_window_set_font(tmp, _DWDefaultFont);
2705 return tmp;
2706 }
2707
2708
2709 /*
2710 * Create a new static text window (widget) to be packed.
2711 * Parameters:
2712 * text: The text to be display by the static text widget.
2713 * id: An ID to be used with dw_window_from_id() or 0L.
2714 */
2715 HWND dw_text_new(const char *text, unsigned long id)
2716 {
2717 GtkWidget *tmp;
2718
2719 tmp = gtk_label_new(text);
2720
2721 /* Left and centered */
2722 gtk_label_set_xalign(GTK_LABEL(tmp), 0.0f);
2723 gtk_label_set_yalign(GTK_LABEL(tmp), 0.5f);
2724 gtk_widget_show(tmp);
2725 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2726 if(_DWDefaultFont)
2727 dw_window_set_font(tmp, _DWDefaultFont);
2728 return tmp;
2729 }
2730
2731 /*
2732 * Create a new status text window (widget) to be packed.
2733 * Parameters:
2734 * text: The text to be display by the static text widget.
2735 * id: An ID to be used with dw_window_from_id() or 0L.
2736 */
2737 HWND dw_status_text_new(const char *text, ULONG id)
2738 {
2739 GtkWidget *tmp, *frame;
2740
2741 frame = gtk_frame_new(NULL);
2742 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
2743 tmp = gtk_label_new(text);
2744 gtk_container_add(GTK_CONTAINER(frame), tmp);
2745 gtk_widget_show(tmp);
2746 gtk_widget_show(frame);
2747
2748 /* Left and centered */
2749 gtk_label_set_xalign(GTK_LABEL(tmp), 0.0f);
2750 gtk_label_set_yalign(GTK_LABEL(tmp), 0.5f);
2751 g_object_set_data(G_OBJECT(frame), "_dw_id", GINT_TO_POINTER(id));
2752 g_object_set_data(G_OBJECT(frame), "_dw_label", (gpointer)tmp);
2753 if(_DWDefaultFont)
2754 dw_window_set_font(tmp, _DWDefaultFont);
2755 return frame;
2756 }
2757
2758 /*
2759 * Create a new Multiline Editbox window (widget) to be packed.
2760 * Parameters:
2761 * id: An ID to be used with dw_window_from_id() or 0L.
2762 */
2763 HWND dw_mle_new(unsigned long id)
2764 {
2765 GtkWidget *tmp, *tmpbox;
2766
2767 tmpbox = gtk_scrolled_window_new (NULL, NULL);
2768 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tmpbox),
2769 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2770 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tmpbox), GTK_SHADOW_ETCHED_IN);
2771 tmp = gtk_text_view_new();
2772 gtk_container_add (GTK_CONTAINER(tmpbox), tmp);
2773 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tmp), GTK_WRAP_WORD);
2774
2775 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2776 g_object_set_data(G_OBJECT(tmpbox), "_dw_user", (gpointer)tmp);
2777 gtk_widget_show(tmp);
2778 gtk_widget_show(tmpbox);
2779 if(_DWDefaultFont)
2780 dw_window_set_font(tmpbox, _DWDefaultFont);
2781 return tmpbox;
2782 }
2783
2784 /*
2785 * Create a new Entryfield window (widget) to be packed.
2786 * Parameters:
2787 * text: The default text to be in the entryfield widget.
2788 * id: An ID to be used with dw_window_from_id() or 0L.
2789 */
2790 HWND dw_entryfield_new(const char *text, unsigned long id)
2791 {
2792 GtkWidget *tmp;
2793
2794 tmp = gtk_entry_new();
2795
2796 gtk_entry_set_text(GTK_ENTRY(tmp), text);
2797 gtk_entry_set_width_chars(GTK_ENTRY(tmp), 0);
2798
2799 gtk_widget_show(tmp);
2800 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2801
2802 if(_DWDefaultFont)
2803 dw_window_set_font(tmp, _DWDefaultFont);
2804 return tmp;
2805 }
2806
2807 /*
2808 * Create a new Entryfield (password) window (widget) to be packed.
2809 * Parameters:
2810 * text: The default text to be in the entryfield widget.
2811 * id: An ID to be used with dw_window_from_id() or 0L.
2812 */
2813 HWND dw_entryfield_password_new(const char *text, ULONG id)
2814 {
2815 GtkWidget *tmp;
2816
2817 tmp = gtk_entry_new();
2818
2819 gtk_entry_set_visibility(GTK_ENTRY(tmp), FALSE);
2820 gtk_entry_set_text(GTK_ENTRY(tmp), text);
2821 gtk_entry_set_width_chars(GTK_ENTRY(tmp), 0);
2822
2823 gtk_widget_show(tmp);
2824 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2825
2826 if(_DWDefaultFont)
2827 dw_window_set_font(tmp, _DWDefaultFont);
2828 return tmp;
2829 }
2830
2831 /*
2832 * Create a new Combobox window (widget) to be packed.
2833 * Parameters:
2834 * text: The default text to be in the combpbox widget.
2835 * id: An ID to be used with dw_window_from_id() or 0L.
2836 */
2837 HWND dw_combobox_new(const char *text, unsigned long id)
2838 {
2839 GtkWidget *tmp;
2840 GtkListStore *store;
2841
2842 store = gtk_list_store_new(1, G_TYPE_STRING);
2843 tmp = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(store));
2844 gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(tmp), 0);
2845 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(tmp))), text);
2846 gtk_entry_set_width_chars(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(tmp))), 0);
2847 gtk_widget_show(tmp);
2848 g_object_set_data(G_OBJECT(tmp), "_dw_tree_type", GINT_TO_POINTER(_DW_TREE_TYPE_COMBOBOX));
2849 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2850 if(_DWDefaultFont)
2851 dw_window_set_font(tmp, _DWDefaultFont);
2852 return tmp;
2853 }
2854
2855 /*
2856 * Create a new button window (widget) to be packed.
2857 * Parameters:
2858 * text: The text to be display by the static text widget.
2859 * id: An ID to be used with dw_window_from_id() or 0L.
2860 */
2861 HWND dw_button_new(const char *text, unsigned long id)
2862 {
2863 GtkWidget *tmp;
2864
2865 tmp = gtk_button_new_with_label(text);
2866 gtk_widget_show(tmp);
2867 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2868 if(_DWDefaultFont)
2869 dw_window_set_font(tmp, _DWDefaultFont);
2870 return tmp;
2871 }
2872
2873 /*
2874 * Create a new bitmap button window (widget) to be packed.
2875 * Parameters:
2876 * text: Bubble help text to be displayed.
2877 * id: An ID of a bitmap in the resource file.
2878 */
2879 HWND dw_bitmapbutton_new(const char *text, unsigned long id)
2880 {
2881 GtkWidget *tmp;
2882 GtkWidget *bitmap;
2883
2884 tmp = gtk_button_new();
2885 bitmap = dw_bitmap_new(id);
2886
2887 if(bitmap)
2888 {
2889 dw_window_set_bitmap(bitmap, id, NULL);
2890 gtk_container_add (GTK_CONTAINER(tmp), bitmap);
2891 g_object_set_data(G_OBJECT(tmp), "_dw_bitmap", bitmap);
2892 }
2893 gtk_widget_show(tmp);
2894 if(text)
2895 {
2896 gtk_widget_set_tooltip_text(tmp, text);
2897 }
2898 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2899 return tmp;
2900 }
2901
2902 /*
2903 * Create a new bitmap button window (widget) to be packed from a file.
2904 * Parameters:
2905 * label_text: Text to display on button. TBD when Windows works
2906 * text: Bubble help text to be displayed.
2907 * id: An ID to be used with dw_window_from_id() or 0L.
2908 * filename: Name of the file, omit extention to have
2909 * DW pick the appropriate file extension.
2910 * (BMP on OS/2 or Windows, XPM on Unix)
2911 */
2912 HWND dw_bitmapbutton_new_from_file(const char *text, unsigned long id, const char *filename)
2913 {
2914 GtkWidget *tmp;
2915 GtkWidget *bitmap;
2916
2917 /* Create a new button */
2918 tmp = gtk_button_new();
2919 /* Now on to the image stuff */
2920 bitmap = dw_bitmap_new(id);
2921 if(bitmap)
2922 {
2923 dw_window_set_bitmap( bitmap, 0, filename );
2924 gtk_container_add (GTK_CONTAINER(tmp), bitmap);
2925 g_object_set_data(G_OBJECT(tmp), "_dw_bitmap", bitmap);
2926 }
2927 gtk_widget_show(tmp);
2928 if(text)
2929 {
2930 gtk_widget_set_tooltip_text(tmp, text);
2931 }
2932 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2933 return tmp;
2934 }
2935
2936 /*
2937 * Create a new bitmap button window (widget) to be packed from data.
2938 * Parameters:
2939 * text: Bubble help text to be displayed.
2940 * id: An ID to be used with dw_window_from_id() or 0L.
2941 * data: Raw data of image.
2942 * (BMP on OS/2 or Windows, XPM on Unix)
2943 * len: Length of raw data
2944 */
2945 HWND dw_bitmapbutton_new_from_data(const char *text, unsigned long id, const char *data, int len)
2946 {
2947 GtkWidget *tmp;
2948 GtkWidget *bitmap;
2949
2950 tmp = gtk_button_new();
2951 bitmap = dw_bitmap_new(id);
2952
2953 if(bitmap)
2954 {
2955 dw_window_set_bitmap_from_data(bitmap, 0, data, len);
2956 gtk_container_add (GTK_CONTAINER(tmp), bitmap);
2957 g_object_set_data(G_OBJECT(tmp), "_dw_bitmap", bitmap);
2958 }
2959 gtk_widget_show(tmp);
2960 if(text)
2961 {
2962 gtk_widget_set_tooltip_text(tmp, text);
2963 }
2964 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2965 return tmp;
2966 }
2967
2968 /*
2969 * Create a new spinbutton window (widget) to be packed.
2970 * Parameters:
2971 * text: The text to be display by the static text widget.
2972 * id: An ID to be used with dw_window_from_id() or 0L.
2973 */
2974 HWND dw_spinbutton_new(const char *text, unsigned long id)
2975 {
2976 GtkAdjustment *adj;
2977 GtkWidget *tmp;
2978
2979 adj = (GtkAdjustment *)gtk_adjustment_new ((float)atoi(text), -65536.0, 65536.0, 1.0, 5.0, 0.0);
2980 tmp = gtk_spin_button_new (adj, 0, 0);
2981 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tmp), TRUE);
2982 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(tmp), TRUE);
2983 gtk_widget_show(tmp);
2984 g_object_set_data(G_OBJECT(tmp), "_dw_adjustment", (gpointer)adj);
2985 g_object_set_data(G_OBJECT(adj), "_dw_spinbutton", (gpointer)tmp);
2986 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
2987 if(_DWDefaultFont)
2988 dw_window_set_font(tmp, _DWDefaultFont);
2989 return tmp;
2990 }
2991
2992 /*
2993 * Create a new radiobutton window (widget) to be packed.
2994 * Parameters:
2995 * text: The text to be display by the static text widget.
2996 * id: An ID to be used with dw_window_from_id() or 0L.
2997 */
2998 HWND dw_radiobutton_new(const char *text, ULONG id)
2999 {
3000 /* This will have to be fixed in the future. */
3001 GtkWidget *tmp;
3002
3003 tmp = gtk_radio_button_new_with_label(NULL, text);
3004 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
3005 gtk_widget_show(tmp);
3006
3007 if(_DWDefaultFont)
3008 dw_window_set_font(tmp, _DWDefaultFont);
3009 return tmp;
3010 }
3011
3012 /*
3013 * Create a new slider window (widget) to be packed.
3014 * Parameters:
3015 * vertical: TRUE or FALSE if slider is vertical.
3016 * increments: Number of increments available.
3017 * id: An ID to be used with dw_window_from_id() or 0L.
3018 */
3019 HWND dw_slider_new(int vertical, int increments, ULONG id)
3020 {
3021 GtkWidget *tmp;
3022 GtkAdjustment *adjustment;
3023
3024 adjustment = (GtkAdjustment *)gtk_adjustment_new(0, 0, (gfloat)increments, 1, 1, 1);
3025 tmp = gtk_scale_new(vertical ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, adjustment);
3026 gtk_widget_show(tmp);
3027 gtk_scale_set_draw_value(GTK_SCALE(tmp), 0);
3028 gtk_scale_set_digits(GTK_SCALE(tmp), 0);
3029 g_object_set_data(G_OBJECT(tmp), "_dw_adjustment", (gpointer)adjustment);
3030 g_object_set_data(G_OBJECT(adjustment), "_dw_slider", (gpointer)tmp);
3031 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
3032 return tmp;
3033 }
3034
3035 /*
3036 * Create a new scrollbar window (widget) to be packed.
3037 * Parameters:
3038 * vertical: TRUE or FALSE if scrollbar is vertical.
3039 * increments: Number of increments available.
3040 * id: An ID to be used with dw_window_from_id() or 0L.
3041 */
3042 HWND dw_scrollbar_new(int vertical, ULONG id)
3043 {
3044 GtkWidget *tmp;
3045 GtkAdjustment *adjustment;
3046
3047 adjustment = (GtkAdjustment *)gtk_adjustment_new(0, 0, 0, 1, 1, 1);
3048 tmp = gtk_scrollbar_new(vertical ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, adjustment);
3049 gtk_widget_set_can_focus(tmp, FALSE);
3050 gtk_widget_show(tmp);
3051 g_object_set_data(G_OBJECT(tmp), "_dw_adjustment", (gpointer)adjustment);
3052 g_object_set_data(G_OBJECT(adjustment), "_dw_scrollbar", (gpointer)tmp);
3053 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
3054 return tmp;
3055 }
3056
3057 /*
3058 * Create a new percent bar window (widget) to be packed.
3059 * Parameters:
3060 * id: An ID to be used with dw_window_from_id() or 0L.
3061 */
3062 HWND dw_percent_new(unsigned long id)
3063 {
3064 GtkWidget *tmp;
3065
3066 tmp = gtk_progress_bar_new();
3067 gtk_widget_show(tmp);
3068 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
3069 return tmp;
3070 }
3071
3072 /*
3073 * Create a new checkbox window (widget) to be packed.
3074 * Parameters:
3075 * text: The text to be display by the static text widget.
3076 * id: An ID to be used with dw_window_from_id() or 0L.
3077 */
3078 HWND dw_checkbox_new(const char *text, unsigned long id)
3079 {
3080 GtkWidget *tmp;
3081
3082 tmp = gtk_check_button_new_with_label(text);
3083 gtk_widget_show(tmp);
3084 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
3085 if(_DWDefaultFont)
3086 dw_window_set_font(tmp, _DWDefaultFont);
3087 return tmp;
3088 }
3089
3090 /*
3091 * Create a new listbox window (widget) to be packed.
3092 * Parameters:
3093 * id: An ID to be used with dw_window_from_id() or 0L.
3094 * multi: Multiple select TRUE or FALSE.
3095 */
3096 HWND dw_listbox_new(unsigned long id, int multi)
3097 {
3098 GtkWidget *tmp, *tree;
3099 GtkListStore *store;
3100 GtkTreeViewColumn *col;
3101 GtkCellRenderer *rend;
3102 GtkTreeSelection *sel;
3103
3104 if(!(tmp = _tree_create(id)))
3105 return 0;
3106 store = gtk_list_store_new(1, G_TYPE_STRING);
3107 tree = _tree_setup(tmp, GTK_TREE_MODEL(store));
3108 g_object_set_data(G_OBJECT(tmp), "_dw_tree_type", GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX));
3109 g_object_set_data(G_OBJECT(tree), "_dw_tree_type", GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX));
3110
3111 col = gtk_tree_view_column_new();
3112 rend = gtk_cell_renderer_text_new();
3113 gtk_tree_view_column_pack_start(col, rend, TRUE);
3114 gtk_tree_view_column_add_attribute(col, rend, "text", 0);
3115
3116 gtk_tree_view_append_column(GTK_TREE_VIEW (tree), col);
3117 gtk_tree_view_set_expander_column(GTK_TREE_VIEW(tree), col);
3118 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE);
3119
3120 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
3121 if(multi)
3122 {
3123 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
3124 }
3125 else
3126 {
3127 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
3128 }
3129 gtk_widget_show(tree);
3130 if(_DWDefaultFont)
3131 dw_window_set_font(tmp, _DWDefaultFont);
3132 return tmp;
3133 }
3134
3135 /*
3136 * Sets the icon used for a given window.
3137 * Parameters:
3138 * handle: Handle to the window.
3139 * id: An ID to be used to specify the icon.
3140 */
3141 void dw_window_set_icon(HWND handle, HICN icon)
3142 {
3143 GdkPixbuf *icon_pixbuf;
3144
3145 icon_pixbuf = _find_pixbuf(icon, NULL, NULL);
3146
3147 if(gtk_widget_get_window(handle) && icon_pixbuf)
3148 {
3149 GList *list = g_list_append(NULL, icon_pixbuf);
3150 gdk_window_set_icon_list(gtk_widget_get_window(handle), list);
3151 g_list_free(list);
3152 }
3153 }
3154
3155 /*
3156 * Sets the bitmap used for a given static window.
3157 * Parameters:
3158 * handle: Handle to the window.
3159 * id: An ID to be used to specify the icon,
3160 * (pass 0 if you use the filename param)
3161 * filename: a path to a file (Bitmap on OS/2 or
3162 * Windows and a pixmap on Unix, pass
3163 * NULL if you use the id param)
3164 */
3165 void dw_window_set_bitmap(HWND handle, unsigned long id, const char *filename)
3166 {
3167 GdkPixbuf *tmp = NULL;
3168 int found_ext = 0;
3169 int i;
3170
3171 if(!id && !filename)
3172 return;
3173
3174 if(id)
3175 tmp = _find_pixbuf((HICN)id, NULL, NULL);
3176 else
3177 {
3178 char *file = alloca(strlen(filename) + 6);
3179
3180 if (!file)
3181 return;
3182
3183 strcpy(file, filename);
3184
3185 /* check if we can read from this file (it exists and read permission) */
3186 if ( access(file, 04 ) != 0 )
3187 {
3188 /* Try with various extentions */
3189 for ( i = 0; i < NUM_EXTS; i++ )
3190 {
3191 strcpy( file, filename );
3192 strcat( file, image_exts[i] );
3193 if ( access( file, 04 ) == 0 )
3194 {
3195 found_ext = 1;
3196 break;
3197 }
3198 }
3199 if ( found_ext == 0 )
3200 return;
3201 }
3202 tmp = gdk_pixbuf_new_from_file(file, NULL );
3203 }
3204
3205 if (tmp)
3206 {
3207 if ( GTK_IS_BUTTON(handle) )
3208 {
3209 GtkWidget *pixmap = (GtkWidget *)g_object_get_data( G_OBJECT(handle), "_dw_bitmap" );
3210 if(pixmap)
3211 {
3212 gtk_image_set_from_pixbuf(GTK_IMAGE(pixmap), tmp);
3213 }
3214 }
3215 else
3216 {
3217 gtk_image_set_from_pixbuf(GTK_IMAGE(handle), tmp);
3218 }
3219 }
3220 }
3221
3222 /*
3223 * Sets the bitmap used for a given static window.
3224 * Parameters:
3225 * handle: Handle to the window.
3226 * id: An ID to be used to specify the icon,
3227 * (pass 0 if you use the filename param)
3228 * data: the image data
3229 * Bitmap on Windows and a pixmap on Unix, pass
3230 * NULL if you use the id param)
3231 * len: length of data
3232 */
3233 void dw_window_set_bitmap_from_data(HWND handle, unsigned long id, const char *data, int len)
3234 {
3235 GdkPixbuf *tmp = NULL;
3236
3237 if(!id && !data)
3238 return;
3239
3240 if(data)
3241 {
3242 /*
3243 * A real hack; create a temporary file and write the contents
3244 * of the data to the file
3245 */
3246 char template[] = "/tmp/dwpixmapXXXXXX";
3247 int written = -1, fd = mkstemp(template);
3248
3249 if(fd != -1)
3250 {
3251 written = write(fd, data, len);
3252 close(fd);
3253 }
3254 /* Bail if we couldn't write full file */
3255 if(fd == -1 || written != len)
3256 return;
3257
3258 tmp = gdk_pixbuf_new_from_file(template, NULL);
3259 /* remove our temporary file */
3260 unlink(template);
3261 }
3262 else if (id)
3263 tmp = _find_pixbuf((HICN)id, NULL, NULL);
3264
3265 if(tmp)
3266 {
3267 if(GTK_IS_BUTTON(handle))
3268 {
3269 GtkWidget *pixmap = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_bitmap");
3270
3271 if(pixmap)
3272 gtk_image_set_from_pixbuf(GTK_IMAGE(pixmap), tmp);
3273 }
3274 else
3275 gtk_image_set_from_pixbuf(GTK_IMAGE(handle), tmp);
3276 }
3277 }
3278
3279 /*
3280 * Sets the text used for a given window.
3281 * Parameters:
3282 * handle: Handle to the window.
3283 * text: The text associated with a given window.
3284 */
3285 void dw_window_set_text(HWND handle, const char *text)
3286 {
3287 GtkWidget *tmp;
3288
3289 if((tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_mdi_title")))
3290 handle = tmp;
3291 if(GTK_IS_ENTRY(handle))
3292 gtk_entry_set_text(GTK_ENTRY(handle), text);
3293 else if(GTK_IS_COMBO_BOX(handle))
3294 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(handle))), text);
3295 else if(GTK_IS_LABEL(handle))
3296 gtk_label_set_text(GTK_LABEL(handle), text);
3297 else if(GTK_IS_BUTTON(handle))
3298 {
3299 gtk_button_set_label(GTK_BUTTON(handle), text);
3300 }
3301 else if(gtk_widget_is_toplevel(handle))
3302 gtk_window_set_title(GTK_WINDOW(handle), text);
3303 else if (GTK_IS_FRAME(handle))
3304 {
3305 /*
3306 * This is a groupbox or status_text
3307 */
3308 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_label");
3309 if ( tmp && GTK_IS_LABEL(tmp) )
3310 gtk_label_set_text(GTK_LABEL(tmp), text);
3311 else /* assume groupbox */
3312 gtk_frame_set_label(GTK_FRAME(handle), text && *text ? text : NULL);
3313 }
3314 }
3315
3316 /*
3317 * Sets the text used for a given window's floating bubble help.
3318 * Parameters:
3319 * handle: Handle to the window (widget).
3320 * bubbletext: The text in the floating bubble tooltip.
3321 */
3322 void API dw_window_set_tooltip(HWND handle, const char *bubbletext)
3323 {
3324 if(bubbletext && *bubbletext)
3325 gtk_widget_set_tooltip_text(handle, bubbletext);
3326 else
3327 gtk_widget_set_has_tooltip(handle, FALSE);
3328 }
3329
3330 /*
3331 * Gets the text used for a given window.
3332 * Parameters:
3333 * handle: Handle to the window.
3334 * Returns:
3335 * text: The text associsated with a given window.
3336 */
3337 char *dw_window_get_text(HWND handle)
3338 {
3339 const char *possible = NULL;
3340
3341 if(GTK_IS_ENTRY(handle))
3342 possible = gtk_entry_get_text(GTK_ENTRY(handle));
3343 else if(GTK_IS_COMBO_BOX(handle))
3344 possible = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(handle))));
3345 else if(GTK_IS_LABEL(handle))
3346 possible = gtk_label_get_text(GTK_LABEL(handle));
3347
3348 return strdup(possible ? possible : "");
3349 }
3350
3351 /*
3352 * Disables given window (widget).
3353 * Parameters:
3354 * handle: Handle to the window.
3355 */
3356 void dw_window_disable(HWND handle)
3357 {
3358 gtk_widget_set_sensitive(handle, FALSE);
3359 }
3360
3361 /*
3362 * Enables given window (widget).
3363 * Parameters:
3364 * handle: Handle to the window.
3365 */
3366 void dw_window_enable(HWND handle)
3367 {
3368 gtk_widget_set_sensitive(handle, TRUE);
3369 }
3370
3371 /*
3372 * Gets the child window handle with specified ID.
3373 * Parameters:
3374 * handle: Handle to the parent window.
3375 * id: Integer ID of the child.
3376 */
3377 HWND API dw_window_from_id(HWND handle, int id)
3378 {
3379 GList *orig = NULL, *list = NULL;
3380
3381 if(handle && GTK_IS_CONTAINER(handle))
3382 {
3383 orig = list = gtk_container_get_children(GTK_CONTAINER(handle));
3384 }
3385 while(list)
3386 {
3387 if(GTK_IS_WIDGET(list->data))
3388 {
3389 if(id == GPOINTER_TO_INT(g_object_get_data(G_OBJECT(list->data), "_dw_id")))
3390 {
3391 HWND ret = (HWND)list->data;
3392 g_list_free(orig);
3393 return ret;
3394 }
3395 }
3396 list = list->next;
3397 }
3398 if(orig)
3399 g_list_free(orig);
3400 return 0L;
3401 }
3402
3403 /*
3404 * Adds text to an MLE box and returns the current point.
3405 * Parameters:
3406 * handle: Handle to the MLE to be queried.
3407 * buffer: Text buffer to be imported.
3408 * startpoint: Point to start entering text.
3409 */
3410 unsigned int dw_mle_import(HWND handle, const char *buffer, int startpoint)
3411 {
3412 unsigned int tmppoint = startpoint;
3413
3414 if(GTK_IS_SCROLLED_WINDOW(handle))
3415 {
3416 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
3417
3418 if(tmp && GTK_IS_TEXT_VIEW(tmp))
3419 {
3420 GtkTextBuffer *tbuffer;
3421 GtkTextIter iter;
3422
3423 tbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tmp));
3424 gtk_text_buffer_get_iter_at_offset(tbuffer, &iter, startpoint);
3425 gtk_text_buffer_place_cursor(tbuffer, &iter);
3426 gtk_text_buffer_insert_at_cursor(tbuffer, buffer, -1);
3427 tmppoint = (startpoint > -1 ? startpoint : 0) + strlen(buffer);
3428 }
3429 }
3430 return tmppoint;
3431 }
3432
3433 /*
3434 * Grabs text from an MLE box.
3435 * Parameters:
3436 * handle: Handle to the MLE to be queried.
3437 * buffer: Text buffer to be exported. MUST allow for trailing nul character.
3438 * startpoint: Point to start grabbing text.
3439 * length: Amount of text to be grabbed.
3440 */
3441 void dw_mle_export(HWND handle, char *buffer, int startpoint, int length)
3442 {
3443 gchar *text;
3444
3445 /* force the return value to nul in case the following tests fail */
3446 if(buffer)
3447 buffer[0] = '\0';
3448 if(GTK_IS_SCROLLED_WINDOW(handle))
3449 {
3450 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
3451
3452 if(tmp && GTK_IS_TEXT_VIEW(tmp))
3453 {
3454 GtkTextBuffer *tbuffer;
3455 GtkTextIter start, end;
3456
3457 tbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tmp));
3458 gtk_text_buffer_get_iter_at_offset(tbuffer, &start, startpoint);
3459 gtk_text_buffer_get_iter_at_offset(tbuffer, &end, startpoint + length);
3460 text = gtk_text_iter_get_text(&start, &end);
3461 if(text) /* Should this get freed? */
3462 {
3463 if(buffer)
3464 strcpy(buffer, text);
3465 }
3466 }
3467 }
3468 }
3469
3470 /*
3471 * Obtains information about an MLE box.
3472 * Parameters:
3473 * handle: Handle to the MLE to be queried.
3474 * bytes: A pointer to a variable to return the total bytes.
3475 * lines: A pointer to a variable to return the number of lines.
3476 */
3477 void dw_mle_get_size(HWND handle, unsigned long *bytes, unsigned long *lines)
3478 {
3479 if(bytes)
3480 *bytes = 0;
3481 if(lines)
3482 *lines = 0;
3483
3484 if(GTK_IS_SCROLLED_WINDOW(handle))
3485 {
3486 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
3487
3488 if(tmp && GTK_IS_TEXT_VIEW(tmp))
3489 {
3490 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tmp));
3491
3492 if(bytes)
3493 *bytes = gtk_text_buffer_get_char_count(buffer);
3494 if(lines)
3495 *lines = gtk_text_buffer_get_line_count(buffer);
3496 }
3497 }
3498 }
3499
3500 /*
3501 * Deletes text from an MLE box.
3502 * Parameters:
3503 * handle: Handle to the MLE to be deleted from.
3504 * startpoint: Point to start deleting text.
3505 * length: Amount of text to be deleted.
3506 */
3507 void dw_mle_delete(HWND handle, int startpoint, int length)
3508 {
3509 if(GTK_IS_SCROLLED_WINDOW(handle))
3510 {
3511 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
3512
3513 if(tmp && GTK_IS_TEXT_VIEW(tmp))
3514 {
3515 GtkTextBuffer *tbuffer;
3516 GtkTextIter start, end;
3517
3518 tbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tmp));
3519 gtk_text_buffer_get_iter_at_offset(tbuffer, &start, startpoint);
3520 gtk_text_buffer_get_iter_at_offset(tbuffer, &end, startpoint + length);
3521 gtk_text_buffer_delete(tbuffer, &start, &end);
3522 }
3523 }
3524 }
3525
3526 /*
3527 * Clears all text from an MLE box.
3528 * Parameters:
3529 * handle: Handle to the MLE to be cleared.
3530 */
3531 void dw_mle_clear(HWND handle)
3532 {
3533 int length;
3534
3535 if(GTK_IS_SCROLLED_WINDOW(handle))
3536 {
3537 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
3538
3539 if(tmp && GTK_IS_TEXT_VIEW(tmp))
3540 {
3541 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tmp));
3542
3543 length = -1;
3544 gtk_text_buffer_set_text(buffer, "", length);
3545 }
3546 }
3547 }
3548
3549 /*
3550 * Sets the visible line of an MLE box.
3551 * Parameters:
3552 * handle: Handle to the MLE.
3553 * line: Line to be visible.
3554 */
3555 void dw_mle_set_visible(HWND handle, int line)
3556 {
3557 if(GTK_IS_SCROLLED_WINDOW(handle))
3558 {
3559 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
3560
3561 if(tmp && GTK_IS_TEXT_VIEW(tmp))
3562 {
3563 GtkTextBuffer *tbuffer;
3564 GtkTextIter iter;
3565 GtkTextMark *mark = (GtkTextMark *)g_object_get_data(G_OBJECT(handle), "_dw_mark");
3566
3567 tbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tmp));
3568 gtk_text_buffer_get_iter_at_offset(tbuffer, &iter, 0);
3569 gtk_text_iter_set_line(&iter, line);
3570 if(!mark)
3571 {
3572 mark = gtk_text_buffer_create_mark(tbuffer, NULL, &iter, FALSE);
3573 g_object_set_data(G_OBJECT(handle), "_dw_mark", (gpointer)mark);
3574 }
3575 else
3576 gtk_text_buffer_move_mark(tbuffer, mark, &iter);
3577 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(tmp), mark,
3578 0, FALSE, 0, 0);
3579 }
3580 }
3581 }
3582
3583 /*
3584 * Sets the editablity of an MLE box.
3585 * Parameters:
3586 * handle: Handle to the MLE.
3587 * state: TRUE if it can be edited, FALSE for readonly.
3588 */
3589 void dw_mle_set_editable(HWND handle, int state)
3590 {
3591 if(GTK_IS_SCROLLED_WINDOW(handle))
3592 {
3593 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
3594
3595 if(tmp && GTK_IS_TEXT_VIEW(tmp))
3596 gtk_text_view_set_editable(GTK_TEXT_VIEW(tmp), state);
3597 }
3598 }
3599
3600 /*
3601 * Sets the word wrap state of an MLE box.
3602 * Parameters:
3603 * handle: Handle to the MLE.
3604 * state: TRUE if it wraps, FALSE if it doesn't.
3605 */
3606 void dw_mle_set_word_wrap(HWND handle, int state)
3607 {
3608 if(GTK_IS_SCROLLED_WINDOW(handle))
3609 {
3610 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
3611
3612 if(tmp && GTK_IS_TEXT_VIEW(tmp))
3613 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tmp), state ? GTK_WRAP_WORD : GTK_WRAP_NONE);
3614 }
3615 }
3616
3617 /*
3618 * Sets the word auto complete state of an MLE box.
3619 * Parameters:
3620 * handle: Handle to the MLE.
3621 * state: Bitwise combination of DW_MLE_COMPLETE_TEXT/DASH/QUOTE
3622 */
3623 void dw_mle_set_auto_complete(HWND handle, int state)
3624 {
3625 }
3626
3627 /*
3628 * Sets the current cursor position of an MLE box.
3629 * Parameters:
3630 * handle: Handle to the MLE to be positioned.
3631 * point: Point to position cursor.
3632 */
3633 void dw_mle_set_cursor(HWND handle, int point)
3634 {
3635 if(GTK_IS_SCROLLED_WINDOW(handle))
3636 {
3637 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
3638
3639 if(tmp && GTK_IS_TEXT_VIEW(tmp))
3640 {
3641 GtkTextBuffer *tbuffer;
3642 GtkTextIter iter;
3643 GtkTextMark *mark = (GtkTextMark *)g_object_get_data(G_OBJECT(handle), "_dw_mark");
3644
3645 tbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tmp));
3646 gtk_text_buffer_get_iter_at_offset(tbuffer, &iter, point);
3647 if(!mark)
3648 {
3649 mark = gtk_text_buffer_create_mark(tbuffer, NULL, &iter, FALSE);
3650 g_object_set_data(G_OBJECT(handle), "_dw_mark", (gpointer)mark);
3651 }
3652 else
3653 gtk_text_buffer_move_mark(tbuffer, mark, &iter);
3654 gtk_text_buffer_place_cursor(tbuffer, &iter);
3655 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(tmp), mark,
3656 0, FALSE, 0, 0);
3657 }
3658 }
3659 }
3660
3661 /*
3662 * Finds text in an MLE box.
3663 * Parameters:
3664 * handle: Handle to the MLE to be cleared.
3665 * text: Text to search for.
3666 * point: Start point of search.
3667 * flags: Search specific flags.
3668 */
3669 int dw_mle_search(HWND handle, const char *text, int point, unsigned long flags)
3670 {
3671 int retval = 0;
3672
3673 if(GTK_IS_SCROLLED_WINDOW(handle))
3674 {
3675 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
3676
3677 if(tmp && GTK_IS_TEXT_VIEW(tmp))
3678 {
3679 GtkTextBuffer *tbuffer;
3680 GtkTextIter iter, found;
3681
3682 tbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tmp));
3683 gtk_text_buffer_get_iter_at_offset(tbuffer, &iter, point);
3684 gtk_text_iter_forward_search(&iter, text, GTK_TEXT_SEARCH_TEXT_ONLY, &found, NULL, NULL);
3685 retval = gtk_text_iter_get_offset(&found);
3686 }
3687 }
3688 return retval;
3689 }
3690
3691 /*
3692 * Stops redrawing of an MLE box.
3693 * Parameters:
3694 * handle: Handle to the MLE to freeze.
3695 */
3696 void dw_mle_freeze(HWND handle)
3697 {
3698 }
3699
3700 /*
3701 * Resumes redrawing of an MLE box.
3702 * Parameters:
3703 * handle: Handle to the MLE to thaw.
3704 */
3705 void dw_mle_thaw(HWND handle)
3706 {
3707 }
3708
3709 /* Internal function to update the progress bar
3710 * while in an indeterminate state.
3711 */
3712 gboolean _dw_update_progress_bar(gpointer data)
3713 {
3714 if(g_object_get_data(G_OBJECT(data), "_dw_alive"))
3715 {
3716 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(data));
3717 return TRUE;
3718 }
3719 return FALSE;
3720 }
3721
3722 /*
3723 * Sets the percent bar position.
3724 * Parameters:
3725 * handle: Handle to the percent bar to be set.
3726 * position: Position of the percent bar withing the range.
3727 */
3728 void dw_percent_set_pos(HWND handle, unsigned int position)
3729 {
3730 if(position == DW_PERCENT_INDETERMINATE)
3731 {
3732 /* Check if we are indeterminate already */
3733 if(!g_object_get_data(G_OBJECT(handle), "_dw_alive"))
3734 {
3735 /* If not become indeterminate... and start a timer to continue */
3736 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(handle));
3737 g_object_set_data(G_OBJECT(handle), "_dw_alive", GINT_TO_POINTER(1));
3738 g_timeout_add(100, (GSourceFunc)_dw_update_progress_bar, (gpointer)handle);
3739 }
3740 }
3741 else
3742 {
3743 /* Cancel the existing timer if one is there */
3744 g_object_set_data(G_OBJECT(handle), "_dw_alive", NULL);
3745 /* Set the position like normal */
3746 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(handle), (gfloat)position/100);
3747 }
3748 }
3749
3750 /*
3751 * Returns the position of the slider.
3752 * Parameters:
3753 * handle: Handle to the slider to be queried.
3754 */
3755 unsigned int dw_slider_get_pos(HWND handle)
3756 {
3757 int val = 0;
3758 GtkAdjustment *adjustment;
3759
3760 if(!handle)
3761 return 0;
3762
3763 adjustment = (GtkAdjustment *)g_object_get_data(G_OBJECT(handle), "_dw_adjustment");
3764 if(adjustment)
3765 {
3766 int max = _round_value(gtk_adjustment_get_upper(adjustment)) - 1;
3767 int thisval = _round_value(gtk_adjustment_get_value(adjustment));
3768
3769 if(gtk_orientable_get_orientation(GTK_ORIENTABLE(handle)) == GTK_ORIENTATION_VERTICAL)
3770 val = max - thisval;
3771 else
3772 val = thisval;
3773 }
3774 return val;
3775 }
3776
3777 /*
3778 * Sets the slider position.
3779 * Parameters:
3780 * handle: Handle to the slider to be set.
3781 * position: Position of the slider withing the range.
3782 */
3783 void dw_slider_set_pos(HWND handle, unsigned int position)
3784 {
3785 GtkAdjustment *adjustment;
3786
3787 if(!handle)
3788 return;
3789
3790 adjustment = (GtkAdjustment *)g_object_get_data(G_OBJECT(handle), "_dw_adjustment");
3791 if(adjustment)
3792 {
3793 int max = _round_value(gtk_adjustment_get_upper(adjustment)) - 1;
3794
3795 if(gtk_orientable_get_orientation(GTK_ORIENTABLE(handle)) == GTK_ORIENTATION_VERTICAL)
3796 gtk_adjustment_set_value(adjustment, (gfloat)(max - position));
3797 else
3798 gtk_adjustment_set_value(adjustment, (gfloat)position);
3799 }
3800 }
3801
3802 /*
3803 * Returns the position of the scrollbar.
3804 * Parameters:
3805 * handle: Handle to the scrollbar to be queried.
3806 */
3807 unsigned int dw_scrollbar_get_pos(HWND handle)
3808 {
3809 int val = 0;
3810 GtkAdjustment *adjustment;
3811
3812 if(!handle)
3813 return 0;
3814
3815 adjustment = (GtkAdjustment *)g_object_get_data(G_OBJECT(handle), "_dw_adjustment");
3816 if(adjustment)
3817 val = _round_value(gtk_adjustment_get_value(adjustment));
3818 return val;
3819 }
3820
3821 /*
3822 * Sets the scrollbar position.
3823 * Parameters:
3824 * handle: Handle to the scrollbar to be set.
3825 * position: Position of the scrollbar withing the range.
3826 */
3827 void dw_scrollbar_set_pos(HWND handle, unsigned int position)
3828 {
3829 GtkAdjustment *adjustment;
3830
3831 if(!handle)
3832 return;
3833
3834 adjustment = (GtkAdjustment *)g_object_get_data(G_OBJECT(handle), "_dw_adjustment");
3835 if(adjustment)
3836 {
3837 g_object_set_data(G_OBJECT(adjustment), "_dw_suppress_value_changed_event", GINT_TO_POINTER(1));
3838 gtk_adjustment_set_value(adjustment, (gfloat)position);
3839 g_object_set_data(G_OBJECT(adjustment), "_dw_suppress_value_changed_event", GINT_TO_POINTER(0));
3840 }
3841 }
3842
3843 /*
3844 * Sets the scrollbar range.
3845 * Parameters:
3846 * handle: Handle to the scrollbar to be set.
3847 * range: Maximum range value.
3848 * visible: Visible area relative to the range.
3849 */
3850 void API dw_scrollbar_set_range(HWND handle, unsigned int range, unsigned int visible)
3851 {
3852 GtkAdjustment *adjustment;
3853
3854 if(!handle)
3855 return;
3856
3857 adjustment = (GtkAdjustment *)g_object_get_data(G_OBJECT(handle), "_dw_adjustment");
3858 if(adjustment)
3859 {
3860 gtk_adjustment_set_upper(adjustment, (gdouble)range);
3861 gtk_adjustment_set_page_increment(adjustment,(gdouble)visible);
3862 gtk_adjustment_set_page_size(adjustment, (gdouble)visible);
3863 }
3864 }
3865
3866 /*
3867 * Sets the spinbutton value.
3868 * Parameters:
3869 * handle: Handle to the spinbutton to be set.
3870 * position: Current value of the spinbutton.
3871 */
3872 void dw_spinbutton_set_pos(HWND handle, long position)
3873 {
3874 gtk_spin_button_set_value(GTK_SPIN_BUTTON(handle), (gfloat)position);
3875 }
3876
3877 /*
3878 * Sets the spinbutton limits.
3879 * Parameters:
3880 * handle: Handle to the spinbutton to be set.
3881 * position: Current value of the spinbutton.
3882 * position: Current value of the spinbutton.
3883 */
3884 void dw_spinbutton_set_limits(HWND handle, long upper, long lower)
3885 {
3886 long curval;
3887 GtkAdjustment *adj;
3888
3889 curval = dw_spinbutton_get_pos(handle);
3890 adj = (GtkAdjustment *)gtk_adjustment_new((gfloat)curval, (gfloat)lower, (gfloat)upper, 1.0, 5.0, 0.0);
3891 gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(handle), adj);
3892 /*
3893 * Set our internal relationships between the adjustment and the spinbutton
3894 */
3895 g_object_set_data(G_OBJECT(handle), "_dw_adjustment", (gpointer)adj);
3896 g_object_set_data(G_OBJECT(adj), "_dw_spinbutton", (gpointer)handle);
3897 }
3898
3899 /*
3900 * Sets the entryfield character limit.
3901 * Parameters:
3902 * handle: Handle to the spinbutton to be set.
3903 * limit: Number of characters the entryfield will take.
3904 */
3905 void dw_entryfield_set_limit(HWND handle, ULONG limit)
3906 {
3907 gtk_entry_set_max_length(GTK_ENTRY(handle), limit);
3908 }
3909
3910 /*
3911 * Returns the current value of the spinbutton.
3912 * Parameters:
3913 * handle: Handle to the spinbutton to be queried.
3914 */
3915 long dw_spinbutton_get_pos(HWND handle)
3916 {
3917 return (long)gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(handle));
3918 }
3919
3920 /*
3921 * Returns the state of the checkbox.
3922 * Parameters:
3923 * handle: Handle to the checkbox to be queried.
3924 */
3925 int dw_checkbox_get(HWND handle)
3926 {
3927 return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(handle));
3928 }
3929
3930 /*
3931 * Sets the state of the checkbox.
3932 * Parameters:
3933 * handle: Handle to the checkbox to be queried.
3934 * value: TRUE for checked, FALSE for unchecked.
3935 */
3936 void dw_checkbox_set(HWND handle, int value)
3937 {
3938 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(handle), value);
3939 }
3940
3941 /*
3942 * Inserts an item into a tree window (widget) after another item.
3943 * Parameters:
3944 * handle: Handle to the tree to be inserted.
3945 * item: Handle to the item to be positioned after.
3946 * title: The text title of the entry.
3947 * icon: Handle to coresponding icon.
3948 * parent: Parent handle or 0 if root.
3949 * itemdata: Item specific data.
3950 */
3951 HTREEITEM dw_tree_insert_after(HWND handle, HTREEITEM item, const char *title, HICN icon, HTREEITEM parent, void *itemdata)
3952 {
3953 GtkWidget *tree;
3954 GtkTreeIter *iter;
3955 GtkTreeStore *store;
3956 GdkPixbuf *pixbuf;
3957 HTREEITEM retval = 0;
3958
3959 if(!handle)
3960 return NULL;
3961
3962 if((tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user"))
3963 && GTK_IS_TREE_VIEW(tree) &&
3964 (store = (GtkTreeStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
3965 {
3966 iter = (GtkTreeIter *)malloc(sizeof(GtkTreeIter));
3967
3968 pixbuf = _find_pixbuf(icon, NULL, NULL);
3969
3970 gtk_tree_store_insert_after(store, iter, (GtkTreeIter *)parent, (GtkTreeIter *)item);
3971 gtk_tree_store_set (store, iter, 0, title, 1, pixbuf, 2, itemdata, 3, iter, -1);
3972 retval = (HTREEITEM)iter;
3973 }
3974 return retval;
3975 }
3976
3977 /*
3978 * Inserts an item into a tree window (widget).
3979 * Parameters:
3980 * handle: Handle to the tree to be inserted.
3981 * title: The text title of the entry.
3982 * icon: Handle to coresponding icon.
3983 * parent: Parent handle or 0 if root.
3984 * itemdata: Item specific data.
3985 */
3986 HTREEITEM dw_tree_insert(HWND handle, const char *title, HICN icon, HTREEITEM parent, void *itemdata)
3987 {
3988 GtkWidget *tree;
3989 GtkTreeIter *iter;
3990 GtkTreeStore *store;
3991 GdkPixbuf *pixbuf;
3992 HTREEITEM retval = 0;
3993
3994 if(!handle)
3995 return NULL;
3996
3997 if((tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user"))
3998 && GTK_IS_TREE_VIEW(tree) &&
3999 (store = (GtkTreeStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4000 {
4001 iter = (GtkTreeIter *)malloc(sizeof(GtkTreeIter));
4002
4003 pixbuf = _find_pixbuf(icon, NULL, NULL);
4004
4005 gtk_tree_store_append (store, iter, (GtkTreeIter *)parent);
4006 gtk_tree_store_set (store, iter, 0, title, 1, pixbuf, 2, itemdata, 3, iter, -1);
4007 retval = (HTREEITEM)iter;
4008 }
4009 return retval;
4010 }
4011
4012 /*
4013 * Sets the text and icon of an item in a tree window (widget).
4014 * Parameters:
4015 * handle: Handle to the tree containing the item.
4016 * item: Handle of the item to be modified.
4017 * title: The text title of the entry.
4018 * icon: Handle to coresponding icon.
4019 */
4020 void dw_tree_item_change(HWND handle, HTREEITEM item, const char *title, HICN icon)
4021 {
4022 GtkWidget *tree;
4023 GtkTreeStore *store;
4024 GdkPixbuf *pixbuf;
4025
4026 if(!handle)
4027 return;
4028
4029 if((tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user"))
4030 && GTK_IS_TREE_VIEW(tree) &&
4031 (store = (GtkTreeStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4032 {
4033 pixbuf = _find_pixbuf(icon, NULL, NULL);
4034
4035 gtk_tree_store_set(store, (GtkTreeIter *)item, 0, title, 1, pixbuf, -1);
4036 }
4037 }
4038
4039 /*
4040 * Sets the item data of a tree item.
4041 * Parameters:
4042 * handle: Handle to the tree containing the item.
4043 * item: Handle of the item to be modified.
4044 * itemdata: User defined data to be associated with item.
4045 */
4046 void dw_tree_item_set_data(HWND handle, HTREEITEM item, void *itemdata)
4047 {
4048 GtkWidget *tree;
4049 GtkTreeStore *store;
4050
4051 if(!handle || !item)
4052 return;
4053
4054 if((tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user"))
4055 && GTK_IS_TREE_VIEW(tree) &&
4056 (store = (GtkTreeStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4057 gtk_tree_store_set(store, (GtkTreeIter *)item, 2, itemdata, -1);
4058 }
4059
4060 /*
4061 * Gets the text an item in a tree window (widget).
4062 * Parameters:
4063 * handle: Handle to the tree containing the item.
4064 * item: Handle of the item to be modified.
4065 */
4066 char * API dw_tree_get_title(HWND handle, HTREEITEM item)
4067 {
4068 char *text = NULL;
4069 GtkWidget *tree;
4070 GtkTreeModel *store;
4071
4072 if(!handle || !item)
4073 return text;
4074
4075 tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
4076
4077 if(tree && GTK_IS_TREE_VIEW(tree) &&
4078 (store = (GtkTreeModel *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4079 gtk_tree_model_get(store, (GtkTreeIter *)item, _DW_DATA_TYPE_STRING, &text, -1);
4080 if(text)
4081 {
4082 char *temp = text;
4083 text = strdup(temp);
4084 g_free(temp);
4085 }
4086 return text;
4087 }
4088
4089 /*
4090 * Gets the text an item in a tree window (widget).
4091 * Parameters:
4092 * handle: Handle to the tree containing the item.
4093 * item: Handle of the item to be modified.
4094 */
4095 HTREEITEM API dw_tree_get_parent(HWND handle, HTREEITEM item)
4096 {
4097 HTREEITEM parent = (HTREEITEM)0;
4098 GtkWidget *tree;
4099 GtkTreeModel *store;
4100
4101 if(!handle || !item)
4102 return parent;
4103
4104 tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
4105
4106 if(tree && GTK_IS_TREE_VIEW(tree) &&
4107 (store = (GtkTreeModel *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4108 {
4109 GtkTreeIter iter;
4110
4111 if(gtk_tree_model_iter_parent(store, &iter, (GtkTreeIter *)item))
4112 gtk_tree_model_get(store, &iter, 3, &parent, -1);
4113 }
4114 return parent;
4115 }
4116
4117 /*
4118 * Gets the item data of a tree item.
4119 * Parameters:
4120 * handle: Handle to the tree containing the item.
4121 * item: Handle of the item to be modified.
4122 */
4123 void *dw_tree_item_get_data(HWND handle, HTREEITEM item)
4124 {
4125 void *ret = NULL;
4126 GtkWidget *tree;
4127 GtkTreeModel *store;
4128
4129 if(!handle || !item)
4130 return NULL;
4131
4132 if((tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user"))
4133 && GTK_IS_TREE_VIEW(tree) &&
4134 (store = (GtkTreeModel *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4135 gtk_tree_model_get(store, (GtkTreeIter *)item, 2, &ret, -1);
4136 return ret;
4137 }
4138
4139 /*
4140 * Sets this item as the active selection.
4141 * Parameters:
4142 * handle: Handle to the tree window (widget) to be selected.
4143 * item: Handle to the item to be selected.
4144 */
4145 void dw_tree_item_select(HWND handle, HTREEITEM item)
4146 {
4147 GtkWidget *tree;
4148 GtkTreeStore *store;
4149
4150 if(!handle || !item)
4151 return;
4152
4153 if((tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user"))
4154 && GTK_IS_TREE_VIEW(tree) &&
4155 (store = (GtkTreeStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4156 {
4157 GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), (GtkTreeIter *)item);
4158 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
4159
4160 gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree), path, NULL, FALSE);
4161 gtk_tree_selection_select_iter(sel, (GtkTreeIter *)item);
4162 gtk_tree_path_free(path);
4163 }
4164 }
4165
4166 static void _dw_recursive_free(GtkTreeModel *store, GtkTreeIter parent)
4167 {
4168 void *data;
4169 GtkTreeIter iter;
4170
4171 gtk_tree_model_get(store, &parent, 3, &data, -1);
4172 if(data)
4173 free(data);
4174 gtk_tree_store_set(GTK_TREE_STORE(store), &parent, 3, NULL, -1);
4175
4176 if(gtk_tree_model_iter_children(store, &iter, &parent))
4177 {
4178 do {
4179 _dw_recursive_free(GTK_TREE_MODEL(store), iter);
4180 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
4181 }
4182 }
4183
4184 /*
4185 * Removes all nodes from a tree.
4186 * Parameters:
4187 * handle: Handle to the window (widget) to be cleared.
4188 */
4189 void dw_tree_clear(HWND handle)
4190 {
4191 GtkWidget *tree;
4192 GtkTreeStore *store;
4193
4194 if(!handle)
4195 return;
4196
4197 if((tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user"))
4198 && GTK_IS_TREE_VIEW(tree) &&
4199 (store = (GtkTreeStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4200 {
4201 GtkTreeIter iter;
4202
4203 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
4204 {
4205 do {
4206 _dw_recursive_free(GTK_TREE_MODEL(store), iter);
4207 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
4208 }
4209 gtk_tree_store_clear(store);
4210 }
4211 }
4212
4213 /*
4214 * Expands a node on a tree.
4215 * Parameters:
4216 * handle: Handle to the tree window (widget).
4217 * item: Handle to node to be expanded.
4218 */
4219 void dw_tree_item_expand(HWND handle, HTREEITEM item)
4220 {
4221 GtkWidget *tree;
4222 GtkTreeStore *store;
4223
4224 if(!handle)
4225 return;
4226
4227 if((tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user"))
4228 && GTK_IS_TREE_VIEW(tree) &&
4229 (store = (GtkTreeStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4230 {
4231 GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), (GtkTreeIter *)item);
4232 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), path, FALSE);
4233 gtk_tree_path_free(path);
4234 }
4235 }
4236
4237 /*
4238 * Collapses a node on a tree.
4239 * Parameters:
4240 * handle: Handle to the tree window (widget).
4241 * item: Handle to node to be collapsed.
4242 */
4243 void dw_tree_item_collapse(HWND handle, HTREEITEM item)
4244 {
4245 GtkWidget *tree;
4246 GtkTreeStore *store;
4247
4248 if(!handle)
4249 return;
4250
4251 if((tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user"))
4252 && GTK_IS_TREE_VIEW(tree) &&
4253 (store = (GtkTreeStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4254 {
4255 GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), (GtkTreeIter *)item);
4256 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree), path);
4257 gtk_tree_path_free(path);
4258 }
4259 }
4260
4261 /*
4262 * Removes a node from a tree.
4263 * Parameters:
4264 * handle: Handle to the window (widget) to be cleared.
4265 * item: Handle to node to be deleted.
4266 */
4267 void dw_tree_item_delete(HWND handle, HTREEITEM item)
4268 {
4269 GtkWidget *tree;
4270 GtkTreeStore *store;
4271
4272 if(!handle)
4273 return;
4274
4275 if((tree = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user"))
4276 && GTK_IS_TREE_VIEW(tree) &&
4277 (store = (GtkTreeStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(tree))))
4278 {
4279 gtk_tree_store_remove(store, (GtkTreeIter *)item);
4280 free(item);
4281 }
4282 }
4283
4284 #define _DW_CONTAINER_STORE_EXTRA 2
4285
4286 static int _dw_container_setup(HWND handle, unsigned long *flags, char **titles, int count, int separator, int extra)
4287 {
4288 int z;
4289 char numbuf[25] = {0};
4290 GtkWidget *tree;
4291 GtkListStore *store;
4292 GtkTreeViewColumn *col;
4293 GtkCellRenderer *rend;
4294 GtkTreeSelection *sel;
4295 GType *array = calloc(count + _DW_CONTAINER_STORE_EXTRA + 1, sizeof(GType));
4296
4297 /* Save some of the info so it is easily accessible */
4298 g_object_set_data(G_OBJECT(handle), "_dw_cont_columns", GINT_TO_POINTER(count));
4299 g_object_set_data(G_OBJECT(handle), "_dw_cont_extra", GINT_TO_POINTER(extra));
4300
4301 /* First param is row title */
4302 array[0] = G_TYPE_STRING;
4303 /* Second param is row data */
4304 array[1] = G_TYPE_POINTER;
4305 array[2] = G_TYPE_POINTER;
4306 /* First loop... create array to create the store */
4307 for(z=0;z<count;z++)
4308 {
4309 if(z == 0 && flags[z] & DW_CFA_STRINGANDICON)
4310 {
4311 array[_DW_CONTAINER_STORE_EXTRA] = GDK_TYPE_PIXBUF;
4312 array[_DW_CONTAINER_STORE_EXTRA+1] = G_TYPE_STRING;
4313 }
4314 else if(flags[z] & DW_CFA_BITMAPORICON)
4315 {
4316 array[z+_DW_CONTAINER_STORE_EXTRA+1] = GDK_TYPE_PIXBUF;
4317 }
4318 else if(flags[z] & DW_CFA_STRING)
4319 {
4320 array[z+_DW_CONTAINER_STORE_EXTRA+1] = G_TYPE_STRING;
4321 }
4322 else if(flags[z] & DW_CFA_ULONG)
4323 {
4324 array[z+_DW_CONTAINER_STORE_EXTRA+1] = G_TYPE_ULONG;
4325 }
4326 else if(flags[z] & DW_CFA_TIME)
4327 {
4328 array[z+_DW_CONTAINER_STORE_EXTRA+1] = G_TYPE_STRING;
4329 }
4330 else if(flags[z] & DW_CFA_DATE)
4331 {
4332 array[z+_DW_CONTAINER_STORE_EXTRA+1] = G_TYPE_STRING;
4333 }
4334 }
4335 /* Create the store and then the tree */
4336 store = gtk_list_store_newv(count + _DW_CONTAINER_STORE_EXTRA + 1, array);
4337 tree = _tree_setup(handle, GTK_TREE_MODEL(store));
4338 g_object_set_data(G_OBJECT(tree), "_dw_tree_type", GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER));
4339 /* Second loop... create the columns */
4340 for(z=0;z<count;z++)
4341 {
4342 snprintf(numbuf, 24, "_dw_cont_col%d", z);
4343 g_object_set_data(G_OBJECT(tree), numbuf, GINT_TO_POINTER(flags[z]));
4344 col = gtk_tree_view_column_new();
4345 rend = NULL;
4346 void **params = calloc(sizeof(void *), 3);
4347
4348 if(z == 0 && flags[z] & DW_CFA_STRINGANDICON)
4349 {
4350 rend = gtk_cell_renderer_pixbuf_new();
4351 gtk_tree_view_column_pack_start(col, rend, FALSE);
4352 gtk_tree_view_column_add_attribute(col, rend, "pixbuf", _DW_CONTAINER_STORE_EXTRA);
4353 rend = gtk_cell_renderer_text_new();
4354 gtk_tree_view_column_pack_start(col, rend, TRUE);
4355 gtk_tree_view_column_add_attribute(col, rend, "text", _DW_CONTAINER_STORE_EXTRA+1);
4356 }
4357 else if(flags[z] & DW_CFA_BITMAPORICON)
4358 {
4359 rend = gtk_cell_renderer_pixbuf_new();
4360 gtk_tree_view_column_pack_start(col, rend, FALSE);
4361 gtk_tree_view_column_add_attribute(col, rend, "pixbuf", z+_DW_CONTAINER_STORE_EXTRA+1);
4362 }
4363 else if(flags[z] & DW_CFA_STRING)
4364 {
4365 rend = gtk_cell_renderer_text_new();
4366 gtk_tree_view_column_pack_start(col, rend, TRUE);
4367 gtk_tree_view_column_add_attribute(col, rend, "text", z+_DW_CONTAINER_STORE_EXTRA+1);
4368 gtk_tree_view_column_set_resizable(col, TRUE);
4369 }
4370 else if(flags[z] & DW_CFA_ULONG)
4371 {
4372 rend = gtk_cell_renderer_text_new();
4373 gtk_tree_view_column_pack_start(col, rend, TRUE);
4374 gtk_tree_view_column_add_attribute(col, rend, "text", z+_DW_CONTAINER_STORE_EXTRA+1);
4375 gtk_tree_view_column_set_resizable(col, TRUE);
4376 }
4377 else if(flags[z] & DW_CFA_TIME)
4378 {
4379 rend = gtk_cell_renderer_text_new();
4380 gtk_tree_view_column_pack_start(col, rend, TRUE);
4381 gtk_tree_view_column_add_attribute(col, rend, "text", z+_DW_CONTAINER_STORE_EXTRA+1);
4382 gtk_tree_view_column_set_resizable(col, TRUE);
4383 }
4384 else if(flags[z] & DW_CFA_DATE)
4385 {
4386 rend = gtk_cell_renderer_text_new();
4387 gtk_tree_view_column_pack_start(col, rend, TRUE);
4388 gtk_tree_view_column_add_attribute(col, rend, "text", z+_DW_CONTAINER_STORE_EXTRA+1);
4389 gtk_tree_view_column_set_resizable(col, TRUE);
4390 }
4391 g_object_set_data(G_OBJECT(col), "_dw_column", GINT_TO_POINTER(z));
4392 params[2] = tree;
4393 g_signal_connect_data(G_OBJECT(col), "clicked", G_CALLBACK(_column_click_event), (gpointer)params, _dw_signal_disconnect, 0);
4394 gtk_tree_view_column_set_title(col, titles[z]);
4395 if(flags[z] & DW_CFA_RIGHT)
4396 {
4397 gtk_tree_view_column_set_alignment(col, 1.0);
4398 if(rend)
4399 gtk_cell_renderer_set_alignment(rend, 1.0, 0.5);
4400 }
4401 else if(flags[z] & DW_CFA_CENTER)
4402 {
4403 gtk_tree_view_column_set_alignment(col, 0.5);
4404 if(rend)
4405 gtk_cell_renderer_set_alignment(rend, 0.5, 0.5);
4406 }
4407 gtk_tree_view_append_column(GTK_TREE_VIEW (tree), col);
4408 }
4409 /* Finish up */
4410 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), TRUE);
4411 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(tree), TRUE);
4412 gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(tree), TRUE);
4413 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
4414 if(g_object_get_data(G_OBJECT(handle), "_dw_multi_sel"))
4415 {
4416 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
4417 }
4418 else
4419 {
4420 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
4421 }
4422 gtk_widget_show(tree);
4423 free(array);
4424 if(_DWDefaultFont)
4425 dw_window_set_font(handle, _DWDefaultFont);
4426 return DW_ERROR_NONE;
4427 }
4428
4429 /*
4430 * Sets up the container columns.
4431 * Parameters:
4432 * handle: Handle to the container to be configured.
4433 * flags: An array of unsigned longs with column flags.
4434 * titles: An array of strings with column text titles.
4435 * count: The number of columns (this should match the arrays).
4436 * separator: The column number that contains the main separator.
4437 * (this item may only be used in OS/2)
4438 */
4439 int dw_container_setup(HWND handle, unsigned long *flags, char **titles, int count, int separator)
4440 {
4441 return _dw_container_setup(handle, flags, titles, count, separator, 0);
4442 }
4443
4444 /*
4445 * Configures the main filesystem columnn title for localization.
4446 * Parameters:
4447 * handle: Handle to the container to be configured.
4448 * title: The title to be displayed in the main column.
4449 */
4450 void API dw_filesystem_set_column_title(HWND handle, const char *title)
4451 {
4452 char *newtitle = strdup(title ? title : "");
4453
4454 g_object_set_data(G_OBJECT(handle), "_dw_coltitle", newtitle);
4455 }
4456
4457 /*
4458 * Sets up the filesystem columns, note: filesystem always has an icon/filename field.
4459 * Parameters:
4460 * handle: Handle to the container to be configured.
4461 * flags: An array of unsigned longs with column flags.
4462 * titles: An array of strings with column text titles.
4463 * count: The number of columns (this should match the arrays).
4464 */
4465 int dw_filesystem_setup(HWND handle, unsigned long *flags, char **titles, int count)
4466 {
4467 char **newtitles = malloc(sizeof(char *) * (count + 1));
4468 unsigned long *newflags = malloc(sizeof(unsigned long) * (count + 1));
4469 char *coltitle = (char *)g_object_get_data(G_OBJECT(handle), "_dw_coltitle");
4470
4471 newtitles[0] = coltitle ? coltitle : "Filename";
4472 newflags[0] = DW_CFA_STRINGANDICON | DW_CFA_LEFT | DW_CFA_HORZSEPARATOR;
4473
4474 memcpy(&newtitles[1], titles, sizeof(char *) * count);
4475 memcpy(&newflags[1], flags, sizeof(unsigned long) * count);
4476
4477 _dw_container_setup(handle, newflags, newtitles, count + 1, 1, 1);
4478
4479 if(coltitle)
4480 {
4481 g_object_set_data(G_OBJECT(handle), "_dw_coltitle", NULL);
4482 free(coltitle);
4483 }
4484 if ( newtitles) free(newtitles);
4485 if ( newflags ) free(newflags);
4486 return DW_ERROR_NONE;
4487 }
4488
4489 /*
4490 * Obtains an icon from a module (or header in GTK).
4491 * Parameters:
4492 * module: Handle to module (DLL) in OS/2 and Windows.
4493 * id: A unsigned long id int the resources on OS/2 and
4494 * Windows, on GTK this is converted to a pointer
4495 * to an embedded XPM.
4496 */
4497 HICN dw_icon_load(unsigned long module, unsigned long id)
4498 {
4499 return (HICN)id;
4500 }
4501
4502 /* Internal function to keep HICNs from getting too big */
4503 GdkPixbuf *_icon_resize(GdkPixbuf *ret)
4504 {
4505 if(ret)
4506 {
4507 int pwidth = gdk_pixbuf_get_width(ret);
4508 int pheight = gdk_pixbuf_get_height(ret);
4509
4510 if(pwidth > 24 || pheight > 24)
4511 {
4512 GdkPixbuf *orig = ret;
4513 ret = gdk_pixbuf_scale_simple(ret, pwidth > 24 ? 24 : pwidth, pheight > 24 ? 24 : pheight, GDK_INTERP_BILINEAR);
4514 g_object_unref(G_OBJECT(orig));
4515 }
4516 }
4517 return ret;
4518 }
4519
4520 /*
4521 * Obtains an icon from a file.
4522 * Parameters:
4523 * filename: Name of the file, omit extention to have
4524 * DW pick the appropriate file extension.
4525 * (ICO on OS/2 or Windows, XPM on Unix)
4526 */
4527 HICN API dw_icon_load_from_file(const char *filename)
4528 {
4529 char *file = alloca(strlen(filename) + 6);
4530 int i, found_ext = 0;
4531
4532 if (!file)
4533 return 0;
4534
4535 strcpy(file, filename);
4536
4537 /* check if we can read from this file (it exists and read permission) */
4538 if (access(file, 04) != 0)
4539 {
4540 /* Try with various extentions */
4541 for ( i = 0; i < NUM_EXTS; i++ )
4542 {
4543 strcpy( file, filename );
4544 strcat( file, image_exts[i] );
4545 if ( access( file, 04 ) == 0 )
4546 {
4547 found_ext = 1;
4548 break;
4549 }
4550 }
4551 if ( found_ext == 0 )
4552 {
4553 return 0;
4554 }
4555 }
4556
4557 return _icon_resize(gdk_pixbuf_new_from_file(file, NULL));
4558 }
4559
4560 /*
4561 * Obtains an icon from data.
4562 * Parameters:
4563 * data: Source of data for image.
4564 * len: length of data
4565 */
4566 HICN API dw_icon_load_from_data(const char *data, int len)
4567 {
4568 int fd, written = -1;
4569 char template[] = "/tmp/dwiconXXXXXX";
4570 HICN ret = 0;
4571
4572 /*
4573 * A real hack; create a temporary file and write the contents
4574 * of the data to the file
4575 */
4576 if((fd = mkstemp(template)) != -1)
4577 {
4578 written = write(fd, data, len);
4579 close(fd);
4580 }
4581 /* Bail if we couldn't write full file */
4582 if(fd == -1 || written != len)
4583 return 0;
4584 ret = _icon_resize(gdk_pixbuf_new_from_file(template, NULL));
4585 unlink(template);
4586 return ret;
4587 }
4588
4589 /*
4590 * Frees a loaded resource in OS/2 and Windows.
4591 * Parameters:
4592 * handle: Handle to icon returned by dw_icon_load().
4593 */
4594 void dw_icon_free(HICN handle)
4595 {
4596 int iicon = GPOINTER_TO_INT(handle);
4597
4598 if(iicon > 65535)
4599 {
4600 g_object_unref(handle);
4601 }
4602 }
4603
4604 /*
4605 * Allocates memory used to populate a container.
4606 * Parameters:
4607 * handle: Handle to the container window (widget).
4608 * rowcount: The number of items to be populated.
4609 */
4610 void *dw_container_alloc(HWND handle, int rowcount)
4611 {
4612 int z, prevrowcount = 0;
4613 GtkWidget *cont;
4614 GtkListStore *store = NULL;
4615
4616 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
4617
4618 /* Make sure it is the correct tree type */
4619 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
4620 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cont));
4621
4622 if(store)
4623 {
4624 GtkTreeIter iter;
4625
4626 prevrowcount = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cont), "_dw_rowcount"));
4627
4628 for(z=0;z<rowcount;z++)
4629 {
4630 gtk_list_store_append(store, &iter);
4631 }
4632 g_object_set_data(G_OBJECT(cont), "_dw_insertpos", GINT_TO_POINTER(prevrowcount));
4633 g_object_set_data(G_OBJECT(cont), "_dw_rowcount", GINT_TO_POINTER(rowcount + prevrowcount));
4634 }
4635 return (void *)cont;
4636 }
4637
4638 /*
4639 * Internal representation of dw_container_set_item() extracted so we can pass
4640 * two data pointers; icon and text for dw_filesystem_set_item().
4641 */
4642 void _dw_container_set_item(HWND handle, void *pointer, int column, int row, void *data)
4643 {
4644 char numbuf[25] = {0}, textbuffer[101] = {0};
4645 int flag = 0;
4646 GtkWidget *cont;
4647 GtkListStore *store = NULL;
4648
4649 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
4650
4651 /* Make sure it is the correct tree type */
4652 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
4653 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cont));
4654
4655 if(store)
4656 {
4657 GtkTreeIter iter;
4658
4659 snprintf(numbuf, 24, "_dw_cont_col%d", column);
4660 flag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cont), numbuf));
4661 if(pointer)
4662 {
4663 row += GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cont), "_dw_insertpos"));
4664 }
4665
4666 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, row))
4667 {
4668 if(flag & DW_CFA_STRINGANDICON)
4669 {
4670 void **thisdata = (void **)data;
4671 HICN hicon = data ? *((HICN *)thisdata[0]) : 0;
4672 char *tmp = data ? (char *)thisdata[1] : NULL;
4673 GdkPixbuf *pixbuf = hicon ? _find_pixbuf(hicon, NULL, NULL) : NULL;
4674
4675 gtk_list_store_set(store, &iter, _DW_CONTAINER_STORE_EXTRA, pixbuf, -1);
4676 gtk_list_store_set(store, &iter, _DW_CONTAINER_STORE_EXTRA + 1, tmp, -1);
4677 }
4678 else if(flag & DW_CFA_BITMAPORICON)
4679 {
4680 HICN hicon = data ? *((HICN *)data) : 0;
4681 GdkPixbuf *pixbuf = hicon ? _find_pixbuf(hicon, NULL, NULL) : NULL;
4682
4683 gtk_list_store_set(store, &iter, column + _DW_CONTAINER_STORE_EXTRA + 1, pixbuf, -1);
4684 }
4685 else if(flag & DW_CFA_STRING)
4686 {
4687 char *tmp = data ? *((char **)data) : NULL;
4688 gtk_list_store_set(store, &iter, column + _DW_CONTAINER_STORE_EXTRA + 1, tmp, -1);
4689 }
4690 else if(flag & DW_CFA_ULONG)
4691 {
4692 ULONG tmp = data ? *((ULONG *)data): 0;
4693
4694 gtk_list_store_set(store, &iter, column + _DW_CONTAINER_STORE_EXTRA + 1, tmp, -1);
4695 }
4696 else if(flag & DW_CFA_DATE)
4697 {
4698 if(data)
4699 {
4700 struct tm curtm;
4701 CDATE cdate = *((CDATE *)data);
4702
4703 memset( &curtm, 0, sizeof(curtm) );
4704 curtm.tm_mday = cdate.day;
4705 curtm.tm_mon = cdate.month - 1;
4706 curtm.tm_year = cdate.year - 1900;
4707
4708 strftime(textbuffer, 100, "%x", &curtm);
4709 }
4710 gtk_list_store_set(store, &iter, column + _DW_CONTAINER_STORE_EXTRA + 1, textbuffer, -1);
4711 }
4712 else if(flag & DW_CFA_TIME)
4713 {
4714 if(data)
4715 {
4716 struct tm curtm;
4717 CTIME ctime = *((CTIME *)data);
4718
4719 memset( &curtm, 0, sizeof(curtm) );
4720 curtm.tm_hour = ctime.hours;
4721 curtm.tm_min = ctime.minutes;
4722 curtm.tm_sec = ctime.seconds;
4723
4724 strftime(textbuffer, 100, "%X", &curtm);
4725 }
4726 gtk_list_store_set(store, &iter, column + _DW_CONTAINER_STORE_EXTRA + 1, textbuffer, -1);
4727 }
4728 }
4729 }
4730 }
4731
4732 /*
4733 * Sets an item in specified row and column to the given data.
4734 * Parameters:
4735 * handle: Handle to the container window (widget).
4736 * pointer: Pointer to the allocated memory in dw_container_alloc().
4737 * column: Zero based column of data being set.
4738 * row: Zero based row of data being set.
4739 * data: Pointer to the data to be added.
4740 */
4741 void dw_container_set_item(HWND handle, void *pointer, int column, int row, void *data)
4742 {
4743 _dw_container_set_item(handle, pointer, column, row, data);
4744 }
4745
4746 /*
4747 * Changes an existing item in specified row and column to the given data.
4748 * Parameters:
4749 * handle: Handle to the container window (widget).
4750 * column: Zero based column of data being set.
4751 * row: Zero based row of data being set.
4752 * data: Pointer to the data to be added.
4753 */
4754 void dw_container_change_item(HWND handle, int column, int row, void *data)
4755 {
4756 _dw_container_set_item(handle, NULL, column, row, data);
4757 }
4758
4759 /*
4760 * Changes an existing item in specified row and column to the given data.
4761 * Parameters:
4762 * handle: Handle to the container window (widget).
4763 * column: Zero based column of data being set.
4764 * row: Zero based row of data being set.
4765 * data: Pointer to the data to be added.
4766 */
4767 void API dw_filesystem_change_item(HWND handle, int column, int row, void *data)
4768 {
4769 dw_filesystem_set_item(handle, NULL, column, row, data);
4770 }
4771
4772 /*
4773 * Changes an item in specified row and column to the given data.
4774 * Parameters:
4775 * handle: Handle to the container window (widget).
4776 * pointer: Pointer to the allocated memory in dw_container_alloc().
4777 * column: Zero based column of data being set.
4778 * row: Zero based row of data being set.
4779 * data: Pointer to the data to be added.
4780 */
4781 void API dw_filesystem_change_file(HWND handle, int row, const char *filename, HICN icon)
4782 {
4783 dw_filesystem_set_file(handle, NULL, row, filename, icon);
4784 }
4785
4786 /*
4787 * Sets an item in specified row and column to the given data.
4788 * Parameters:
4789 * handle: Handle to the container window (widget).
4790 * pointer: Pointer to the allocated memory in dw_container_alloc().
4791 * column: Zero based column of data being set.
4792 * row: Zero based row of data being set.
4793 * data: Pointer to the data to be added.
4794 */
4795 void dw_filesystem_set_file(HWND handle, void *pointer, int row, const char *filename, HICN icon)
4796 {
4797 void *data[2] = { (void *)&icon, (void *)filename };
4798
4799 _dw_container_set_item(handle, pointer, 0, row, (void *)data);
4800 }
4801
4802 /*
4803 * Sets an item in specified row and column to the given data.
4804 * Parameters:
4805 * handle: Handle to the container window (widget).
4806 * pointer: Pointer to the allocated memory in dw_container_alloc().
4807 * column: Zero based column of data being set.
4808 * row: Zero based row of data being set.
4809 * data: Pointer to the data to be added.
4810 */
4811 void dw_filesystem_set_item(HWND handle, void *pointer, int column, int row, void *data)
4812 {
4813 _dw_container_set_item(handle, pointer, column + 1, row, data);
4814 }
4815
4816 /*
4817 * Gets column type for a container column
4818 * Parameters:
4819 * handle: Handle to the container window (widget).
4820 * column: Zero based column.
4821 */
4822 int dw_container_get_column_type(HWND handle, int column)
4823 {
4824 char numbuf[25] = {0};
4825 int flag, rc = 0;
4826 GtkWidget *cont = handle;
4827
4828 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
4829 if(!cont)
4830 return 0;
4831
4832 snprintf(numbuf, 24, "_dw_cont_col%d", column);
4833 flag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cont), numbuf));
4834
4835 if(flag & DW_CFA_BITMAPORICON)
4836 rc = DW_CFA_BITMAPORICON;
4837 else if(flag & DW_CFA_STRING)
4838 rc = DW_CFA_STRING;
4839 else if(flag & DW_CFA_ULONG)
4840 rc = DW_CFA_ULONG;
4841 else if(flag & DW_CFA_DATE)
4842 rc = DW_CFA_DATE;
4843 else if(flag & DW_CFA_TIME)
4844 rc = DW_CFA_TIME;
4845 else
4846 rc = 0;
4847 return rc;
4848 }
4849
4850 /*
4851 * Gets column type for a filesystem container column
4852 * Parameters:
4853 * handle: Handle to the container window (widget).
4854 * column: Zero based column.
4855 */
4856 int API dw_filesystem_get_column_type(HWND handle, int column)
4857 {
4858 return dw_container_get_column_type( handle, column + 1 );
4859 }
4860
4861 /*
4862 * Sets the alternating row colors for container window (widget) handle.
4863 * Parameters:
4864 * handle: The window (widget) handle.
4865 * oddcolor: Odd row background color in DW_RGB format or a default color index.
4866 * evencolor: Even row background color in DW_RGB format or a default color index.
4867 * DW_RGB_TRANSPARENT will disable coloring rows.
4868 * DW_CLR_DEFAULT will use the system default alternating row colors.
4869 */
4870 void API dw_container_set_stripe(HWND handle, unsigned long oddcolor, unsigned long evencolor)
4871 {
4872 }
4873
4874 /*
4875 * Sets the width of a column in the container.
4876 * Parameters:
4877 * handle: Handle to window (widget) of container.
4878 * column: Zero based column of width being set.
4879 * width: Width of column in pixels.
4880 */
4881 void dw_container_set_column_width(HWND handle, int column, int width)
4882 {
4883 GtkWidget *cont;
4884
4885 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
4886
4887 /* Make sure it is the correct tree type */
4888 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
4889 {
4890 GtkTreeViewColumn *col = gtk_tree_view_get_column(GTK_TREE_VIEW(cont), column);
4891
4892 if(col && GTK_IS_TREE_VIEW_COLUMN(col))
4893 {
4894 gtk_tree_view_column_set_fixed_width(GTK_TREE_VIEW_COLUMN(col), width);
4895 }
4896 }
4897 }
4898
4899 /* Internal version for both */
4900 void _dw_container_set_row_data(HWND handle, void *pointer, int row, int type, void *data)
4901 {
4902 GtkWidget *cont = handle;
4903 GtkListStore *store = NULL;
4904
4905 /* Make sure it is the correct tree type */
4906 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
4907 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cont));
4908
4909 if(store)
4910 {
4911 GtkTreeIter iter;
4912
4913 if(pointer)
4914 {
4915 row += GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cont), "_dw_insertpos"));
4916 }
4917
4918 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, row))
4919 {
4920 gtk_list_store_set(store, &iter, type, (gpointer)data, -1);
4921 }
4922 }
4923 }
4924
4925 /*
4926 * Sets the title of a row in the container.
4927 * Parameters:
4928 * pointer: Pointer to the allocated memory in dw_container_alloc().
4929 * row: Zero based row of data being set.
4930 * title: String title of the item.
4931 */
4932 void dw_container_set_row_title(void *pointer, int row, const char *title)
4933 {
4934 _dw_container_set_row_data(pointer, pointer, row, _DW_DATA_TYPE_STRING, (void *)title);
4935 }
4936
4937 /*
4938 * Changes the title of a row already inserted in the container.
4939 * Parameters:
4940 * handle: Handle to window (widget) of container.
4941 * row: Zero based row of data being set.
4942 * title: String title of the item.
4943 */
4944 void dw_container_change_row_title(HWND handle, int row, const char *title)
4945 {
4946 _dw_container_set_row_data(handle, NULL, row, _DW_DATA_TYPE_STRING, (void *)title);
4947 }
4948
4949 /*
4950 * Sets the data of a row in the container.
4951 * Parameters:
4952 * pointer: Pointer to the allocated memory in dw_container_alloc().
4953 * row: Zero based row of data being set.
4954 * data: Data pointer.
4955 */
4956 void dw_container_set_row_data(void *pointer, int row, void *data)
4957 {
4958 _dw_container_set_row_data(pointer, pointer, row, _DW_DATA_TYPE_POINTER, data);
4959 }
4960
4961 /*
4962 * Changes the data of a row already inserted in the container.
4963 * Parameters:
4964 * handle: Handle to window (widget) of container.
4965 * row: Zero based row of data being set.
4966 * data: Data pointer.
4967 */
4968 void dw_container_change_row_data(HWND handle, int row, void *data)
4969 {
4970 _dw_container_set_row_data(handle, NULL, row, _DW_DATA_TYPE_POINTER, data);
4971 }
4972
4973 /*
4974 * Sets the title of a row in the container.
4975 * Parameters:
4976 * handle: Handle to the container window (widget).
4977 * pointer: Pointer to the allocated memory in dw_container_alloc().
4978 * rowcount: The number of rows to be inserted.
4979 */
4980 void dw_container_insert(HWND handle, void *pointer, int rowcount)
4981 {
4982 /* Don't need to do anything here */
4983 }
4984
4985 /*
4986 * Removes the first x rows from a container.
4987 * Parameters:
4988 * handle: Handle to the window (widget) to be deleted from.
4989 * rowcount: The number of rows to be deleted.
4990 */
4991 void dw_container_delete(HWND handle, int rowcount)
4992 {
4993 GtkWidget *cont;
4994 GtkListStore *store = NULL;
4995
4996 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
4997
4998 /* Make sure it is the correct tree type */
4999 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
5000 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cont));
5001
5002 if(store)
5003 {
5004 GtkTreeIter iter;
5005 int rows, z;
5006
5007 rows = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cont), "_dw_rowcount"));
5008
5009 for(z=0;z<rowcount;z++)
5010 {
5011 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, 0))
5012 gtk_list_store_remove(store, &iter);
5013 }
5014
5015 if(rows - rowcount < 0)
5016 rows = 0;
5017 else
5018 rows -= rowcount;
5019
5020 g_object_set_data(G_OBJECT(cont), "_dw_rowcount", GINT_TO_POINTER(rows));
5021 }
5022 }
5023
5024 /*
5025 * Removes all rows from a container.
5026 * Parameters:
5027 * handle: Handle to the window (widget) to be cleared.
5028 * redraw: TRUE to cause the container to redraw immediately.
5029 */
5030 void dw_container_clear(HWND handle, int redraw)
5031 {
5032 GtkWidget *cont;
5033 GtkListStore *store = NULL;
5034
5035 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
5036
5037 /* Make sure it is the correct tree type */
5038 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
5039 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cont));
5040
5041 if(store)
5042 {
5043 g_object_set_data(G_OBJECT(cont), "_dw_rowcount", GINT_TO_POINTER(0));
5044 g_object_set_data(G_OBJECT(cont), "_dw_insertpos", GINT_TO_POINTER(0));
5045
5046 gtk_list_store_clear(store);
5047 }
5048 }
5049
5050 /*
5051 * Scrolls container up or down.
5052 * Parameters:
5053 * handle: Handle to the window (widget) to be scrolled.
5054 * direction: DW_SCROLL_UP, DW_SCROLL_DOWN, DW_SCROLL_TOP or
5055 * DW_SCROLL_BOTTOM. (rows is ignored for last two)
5056 * rows: The number of rows to be scrolled.
5057 */
5058 void dw_container_scroll(HWND handle, int direction, long rows)
5059 {
5060 GtkWidget *cont;
5061
5062 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
5063
5064 /* Make sure it is the correct tree type */
5065 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
5066 {
5067 GtkAdjustment *adjust = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(cont));
5068
5069 if(adjust)
5070 {
5071 gint rowcount = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cont), "_dw_rowcount"));
5072 gdouble currpos = gtk_adjustment_get_value(adjust);
5073 gdouble upper = gtk_adjustment_get_upper(adjust);
5074 gdouble lower = gtk_adjustment_get_lower(adjust);
5075 gdouble change;
5076
5077 /* Safety check */
5078 if(rowcount < 1)
5079 return;
5080
5081 change = ((gdouble)rows/(gdouble)rowcount) * (upper - lower);
5082
5083 switch(direction)
5084 {
5085 case DW_SCROLL_TOP:
5086 {
5087 gtk_adjustment_set_value(adjust, lower);
5088 break;
5089 }
5090 case DW_SCROLL_BOTTOM:
5091 {
5092 gtk_adjustment_set_value(adjust, upper);
5093 break;
5094 }
5095 case DW_SCROLL_UP:
5096 {
5097 gdouble newpos = currpos - change;
5098 if(newpos < lower)
5099 {
5100 newpos = lower;
5101 }
5102 gtk_adjustment_set_value(adjust, newpos);
5103 break;
5104 }
5105 case DW_SCROLL_DOWN:
5106 {
5107 gdouble newpos = currpos + change;
5108 if(newpos > upper)
5109 {
5110 newpos = upper;
5111 }
5112 gtk_adjustment_set_value(adjust, newpos);
5113 break;
5114 }
5115 }
5116 }
5117 }
5118 }
5119
5120 /*
5121 * Starts a new query of a container.
5122 * Parameters:
5123 * handle: Handle to the window (widget) to be queried.
5124 * flags: If this parameter is DW_CRA_SELECTED it will only
5125 * return items that are currently selected. Otherwise
5126 * it will return all records in the container.
5127 */
5128 char *dw_container_query_start(HWND handle, unsigned long flags)
5129 {
5130 GtkWidget *cont;
5131 GtkListStore *store = NULL;
5132 char *retval = NULL;
5133 int type = flags & DW_CR_RETDATA ? _DW_DATA_TYPE_POINTER : _DW_DATA_TYPE_STRING;
5134
5135 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
5136
5137 /* Make sure it is the correct tree type */
5138 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
5139 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cont));
5140
5141 if(store)
5142 {
5143 /* These should be separate but right now this will work */
5144 if(flags & DW_CRA_SELECTED)
5145 {
5146 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(cont));
5147 GList *list = gtk_tree_selection_get_selected_rows(sel, NULL);
5148 if(list)
5149 {
5150 GtkTreePath *path = g_list_nth_data(list, 0);
5151
5152 if(path)
5153 {
5154 gint *indices = gtk_tree_path_get_indices(path);
5155
5156 if(indices)
5157 {
5158 GtkTreeIter iter;
5159
5160 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, indices[0]))
5161 {
5162 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, type, &retval, -1);
5163 g_object_set_data(G_OBJECT(cont), "_dw_querypos", GINT_TO_POINTER(1));
5164 }
5165 }
5166 }
5167 g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
5168 g_list_free(list);
5169 }
5170 }
5171 else if(flags & DW_CRA_CURSORED)
5172 {
5173 GtkTreePath *path;
5174
5175 gtk_tree_view_get_cursor(GTK_TREE_VIEW(cont), &path, NULL);
5176 if(path)
5177 {
5178 GtkTreeIter iter;
5179
5180 if(gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
5181 {
5182 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, type, &retval, -1);
5183 }
5184 gtk_tree_path_free(path);
5185 }
5186 }
5187 else
5188 {
5189 GtkTreeIter iter;
5190
5191 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, 0))
5192 {
5193 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, type, &retval, -1);
5194 g_object_set_data(G_OBJECT(cont), "_dw_querypos", GINT_TO_POINTER(1));
5195 }
5196 }
5197 }
5198 /* If there is a title, duplicate it and free the temporary copy */
5199 if(retval && type == _DW_DATA_TYPE_STRING)
5200 {
5201 char *temp = retval;
5202 retval = strdup(temp);
5203 g_free(temp);
5204 }
5205 return retval;
5206 }
5207
5208 /*
5209 * Continues an existing query of a container.
5210 * Parameters:
5211 * handle: Handle to the window (widget) to be queried.
5212 * flags: If this parameter is DW_CRA_SELECTED it will only
5213 * return items that are currently selected. Otherwise
5214 * it will return all records in the container.
5215 */
5216 char *dw_container_query_next(HWND handle, unsigned long flags)
5217 {
5218 GtkWidget *cont;
5219 GtkListStore *store = NULL;
5220 char *retval = NULL;
5221 int type = flags & DW_CR_RETDATA ? _DW_DATA_TYPE_POINTER : _DW_DATA_TYPE_STRING;
5222
5223 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
5224
5225 /* Make sure it is the correct tree type */
5226 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
5227 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cont));
5228
5229 if(store)
5230 {
5231 int pos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cont), "_dw_querypos"));
5232 int count = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
5233
5234 /* These should be separate but right now this will work */
5235 if(flags & DW_CRA_SELECTED)
5236 {
5237 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(cont));
5238 GList *list = gtk_tree_selection_get_selected_rows(sel, NULL);
5239
5240 if(list)
5241 {
5242 GtkTreePath *path = g_list_nth_data(list, pos);
5243
5244 if(path)
5245 {
5246 gint *indices = gtk_tree_path_get_indices(path);
5247
5248 if(indices)
5249 {
5250 GtkTreeIter iter;
5251
5252 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, indices[0]))
5253 {
5254 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, type, &retval, -1);
5255 g_object_set_data(G_OBJECT(cont), "_dw_querypos", GINT_TO_POINTER(pos+1));
5256 }
5257 }
5258 }
5259 g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
5260 g_list_free(list);
5261 }
5262 }
5263 else if(flags & DW_CRA_CURSORED)
5264 {
5265 /* There will only be one item cursored,
5266 * retrieve it with dw_container_query_start()
5267 */
5268 retval = NULL;
5269 }
5270 else
5271 {
5272 GtkTreeIter iter;
5273
5274 if(pos < count && gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, pos))
5275 {
5276 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, type, &retval, -1);
5277 g_object_set_data(G_OBJECT(cont), "_dw_querypos", GINT_TO_POINTER(pos+1));
5278 }
5279 }
5280 }
5281 /* If there is a title, duplicate it and free the temporary copy */
5282 if(retval && type == _DW_DATA_TYPE_STRING)
5283 {
5284 char *temp = retval;
5285 retval = strdup(temp);
5286 g_free(temp);
5287 }
5288 return retval;
5289 }
5290
5291 int _find_iter(GtkListStore *store, GtkTreeIter *iter, void *data, int textcomp)
5292 {
5293 int z, rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
5294 void *thisdata;
5295 int retval = FALSE;
5296
5297 for(z=0;z<rows;z++)
5298 {
5299 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), iter, NULL, z))
5300 {
5301 /* Get either string from position 0 or pointer from position 1 */
5302 gtk_tree_model_get(GTK_TREE_MODEL(store), iter, textcomp ? _DW_DATA_TYPE_STRING : _DW_DATA_TYPE_POINTER, &thisdata, -1);
5303 if((textcomp && thisdata && strcmp((char *)thisdata, (char *)data) == 0) || (!textcomp && thisdata == data))
5304 {
5305 retval = TRUE;
5306 z = rows;
5307 }
5308 if(textcomp && thisdata)
5309 g_free(thisdata);
5310 }
5311 }
5312 return retval;
5313 }
5314
5315 void _dw_container_cursor(HWND handle, void *data, int textcomp)
5316 {
5317 GtkWidget *cont;
5318 GtkListStore *store = NULL;
5319
5320 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
5321
5322 /* Make sure it is the correct tree type */
5323 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
5324 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cont));
5325
5326 if(store)
5327 {
5328 GtkTreeIter iter;
5329
5330 if(_find_iter(store, &iter, data, textcomp))
5331 {
5332 GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
5333
5334 if(path)
5335 {
5336 gtk_tree_view_row_activated(GTK_TREE_VIEW(cont), path, NULL);
5337 gtk_tree_path_free(path);
5338 }
5339 }
5340 }
5341 }
5342
5343 /*
5344 * Cursors the item with the text speficied, and scrolls to that item.
5345 * Parameters:
5346 * handle: Handle to the window (widget) to be queried.
5347 * text: Text usually returned by dw_container_query().
5348 */
5349 void dw_container_cursor(HWND handle, const char *text)
5350 {
5351 _dw_container_cursor(handle, (void *)text, TRUE);
5352 }
5353
5354 /*
5355 * Cursors the item with the text speficied, and scrolls to that item.
5356 * Parameters:
5357 * handle: Handle to the window (widget) to be queried.
5358 * text: Text usually returned by dw_container_query().
5359 */
5360 void dw_container_cursor_by_data(HWND handle, void *data)
5361 {
5362 _dw_container_cursor(handle, data, FALSE);
5363 }
5364
5365 void _dw_container_delete_row(HWND handle, void *data, int textcomp)
5366 {
5367 GtkWidget *cont;
5368 GtkListStore *store = NULL;
5369
5370 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
5371
5372 /* Make sure it is the correct tree type */
5373 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
5374 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cont));
5375
5376 if(store)
5377 {
5378 GtkTreeIter iter;
5379 int rows = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cont), "_dw_rowcount"));
5380
5381 if(_find_iter(store, &iter, data, textcomp))
5382 {
5383 gtk_list_store_remove(store, &iter);
5384 rows--;
5385 }
5386
5387 g_object_set_data(G_OBJECT(cont), "_dw_rowcount", GINT_TO_POINTER(rows));
5388 }
5389 }
5390
5391 /*
5392 * Deletes the item with the text speficied.
5393 * Parameters:
5394 * handle: Handle to the window (widget).
5395 * text: Text usually returned by dw_container_query().
5396 */
5397 void dw_container_delete_row(HWND handle, const char *text)
5398 {
5399 _dw_container_delete_row(handle, (void *)text, TRUE);
5400 }
5401
5402 /*
5403 * Deletes the item with the text speficied.
5404 * Parameters:
5405 * handle: Handle to the window (widget).
5406 * text: Text usually returned by dw_container_query().
5407 */
5408 void dw_container_delete_row_by_data(HWND handle, void *data)
5409 {
5410 _dw_container_delete_row(handle, data, FALSE);
5411 }
5412
5413 /*
5414 * Optimizes the column widths so that all data is visible.
5415 * Parameters:
5416 * handle: Handle to the window (widget) to be optimized.
5417 */
5418 void dw_container_optimize(HWND handle)
5419 {
5420 GtkWidget *cont;
5421
5422 cont = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
5423
5424 /* Make sure it is the correct tree type */
5425 if(cont && GTK_IS_TREE_VIEW(cont) && g_object_get_data(G_OBJECT(cont), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_CONTAINER))
5426 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(cont));
5427 }
5428
5429 /* Translate the status message into a message on our buddy window */
5430 static void _status_translate(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data)
5431 {
5432 GdkEventButton event = { 0 };
5433 long x, y;
5434 gboolean retval;
5435
5436 dw_pointer_query_pos(&x, &y);
5437
5438 event.button = button;
5439 event.x = x;
5440 event.y = y;
5441
5442 g_signal_emit_by_name(G_OBJECT(user_data), "button_press_event", &event, &retval);
5443 }
5444
5445 /*
5446 * Inserts an icon into the taskbar.
5447 * Parameters:
5448 * handle: Window handle that will handle taskbar icon messages.
5449 * icon: Icon handle to display in the taskbar.
5450 * bubbletext: Text to show when the mouse is above the icon.
5451 */
5452 void dw_taskbar_insert(HWND handle, HICN icon, const char *bubbletext)
5453 {
5454 GtkStatusIcon *status;
5455 GdkPixbuf *pixbuf;
5456
5457 pixbuf = _find_pixbuf(icon, NULL, NULL);
5458 status = gtk_status_icon_new_from_pixbuf(pixbuf);
5459 if(bubbletext)
5460 gtk_status_icon_set_tooltip_text(status, bubbletext);
5461 g_object_set_data(G_OBJECT(handle), "_dw_taskbar", status);
5462 g_signal_connect(G_OBJECT (status), "popup-menu", G_CALLBACK (_status_translate), handle);
5463 gtk_status_icon_set_visible(status, TRUE);
5464 }
5465
5466 /*
5467 * Deletes an icon from the taskbar.
5468 * Parameters:
5469 * handle: Window handle that was used with dw_taskbar_insert().
5470 * icon: Icon handle that was used with dw_taskbar_insert().
5471 */
5472 void dw_taskbar_delete(HWND handle, HICN icon)
5473 {
5474 GtkStatusIcon *status;
5475
5476 status = g_object_get_data(G_OBJECT(handle), "_dw_taskbar");
5477 g_object_unref(G_OBJECT(status));
5478 }
5479
5480 /*
5481 * Creates a rendering context widget (window) to be packed.
5482 * Parameters:
5483 * id: An id to be used with dw_window_from_id.
5484 * Returns:
5485 * A handle to the widget or NULL on failure.
5486 */
5487 HWND dw_render_new(unsigned long id)
5488 {
5489 GtkWidget *tmp;
5490
5491 tmp = gtk_drawing_area_new();
5492 gtk_widget_set_events(tmp, GDK_EXPOSURE_MASK
5493 | GDK_LEAVE_NOTIFY_MASK
5494 | GDK_BUTTON_PRESS_MASK
5495 | GDK_BUTTON_RELEASE_MASK
5496 | GDK_KEY_PRESS_MASK
5497 | GDK_POINTER_MOTION_MASK
5498 | GDK_POINTER_MOTION_HINT_MASK);
5499 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
5500 gtk_widget_set_can_focus(tmp, TRUE);
5501 gtk_widget_show(tmp);
5502 if(_DWDefaultFont)
5503 dw_window_set_font(tmp, _DWDefaultFont);
5504 return tmp;
5505 }
5506
5507 /* Returns a GdkRGBA from a DW color */
5508 static GdkRGBA _internal_color(unsigned long value)
5509 {
5510 if(DW_RGB_COLOR & value)
5511 {
5512 GdkRGBA color = { (gfloat)DW_RED_VALUE(value) / 255.0, (gfloat)DW_GREEN_VALUE(value) / 255.0, (gfloat)DW_BLUE_VALUE(value) / 255.0, 1.0 };
5513 return color;
5514 }
5515 if (value < 16)
5516 return _colors[value];
5517 return _colors[0];
5518 }
5519
5520 /* Sets the current foreground drawing color.
5521 * Parameters:
5522 * red: red value.
5523 * green: green value.
5524 * blue: blue value.
5525 */
5526 void dw_color_foreground_set(unsigned long value)
5527 {
5528 GdkRGBA color = _internal_color(value);
5529 GdkRGBA *foreground = pthread_getspecific(_dw_fg_color_key);
5530
5531 *foreground = color;
5532 }
5533
5534 /* Sets the current background drawing color.
5535 * Parameters:
5536 * red: red value.
5537 * green: green value.
5538 * blue: blue value.
5539 */
5540 void dw_color_background_set(unsigned long value)
5541 {
5542 GdkRGBA *background = pthread_getspecific(_dw_bg_color_key);
5543
5544 if(value == DW_CLR_DEFAULT)
5545 {
5546 if(background)
5547 {
5548 pthread_setspecific(_dw_bg_color_key, NULL);
5549 free(background);
5550 }
5551 }
5552 else
5553 {
5554 GdkRGBA color = _internal_color(value);
5555
5556 if(!background)
5557 {
5558 background = malloc(sizeof(GdkRGBA));
5559 pthread_setspecific(_dw_bg_color_key, background);
5560 }
5561 *background = color;
5562 }
5563 }
5564
5565 /* Allows the user to choose a color using the system's color chooser dialog.
5566 * Parameters:
5567 * value: current color
5568 * Returns:
5569 * The selected color or the current color if cancelled.
5570 */
5571 unsigned long API dw_color_choose(unsigned long value)
5572 {
5573 GtkColorChooser *cd;
5574 GdkRGBA color = _internal_color(value);
5575 unsigned long retcolor = value;
5576
5577 cd = (GtkColorChooser *)gtk_color_chooser_dialog_new("Choose color", NULL);
5578 gtk_color_chooser_set_use_alpha(cd, FALSE);
5579 gtk_color_chooser_set_rgba(cd, &color);
5580
5581 gtk_widget_show(GTK_WIDGET(cd));
5582
5583 if(gtk_dialog_run(GTK_DIALOG(cd)) == GTK_RESPONSE_OK)
5584 {
5585 gtk_color_chooser_get_rgba(cd, &color);
5586 retcolor = DW_RGB((int)(color.red * 255), (int)(color.green * 255), (int)(color.blue * 255));
5587 }
5588 gtk_widget_destroy(GTK_WIDGET(cd));
5589 return retcolor;
5590 }
5591
5592 /* Draw a point on a window (preferably a render window).
5593 * Parameters:
5594 * handle: Handle to the window.
5595 * pixmap: Handle to the pixmap. (choose only one of these)
5596 * x: X coordinate.
5597 * y: Y coordinate.
5598 */
5599 void dw_draw_point(HWND handle, HPIXMAP pixmap, int x, int y)
5600 {
5601 cairo_t *cr = NULL;
5602 GdkDrawingContext *dc = NULL;
5603 cairo_region_t *clip = NULL;
5604
5605 if(handle)
5606 {
5607 GdkWindow *window = gtk_widget_get_window(handle);
5608 /* Safety check for non-existant windows */
5609 if(!window || !GDK_IS_WINDOW(window))
5610 return;
5611 clip = gdk_window_get_clip_region(window);
5612 dc = gdk_window_begin_draw_frame(window, clip);
5613 cr = gdk_drawing_context_get_cairo_context(dc);
5614 }
5615 else if(pixmap)
5616 cr = cairo_create(pixmap->image);
5617 if(cr)
5618 {
5619 GdkRGBA *foreground = pthread_getspecific(_dw_fg_color_key);
5620
5621 gdk_cairo_set_source_rgba(cr, foreground);
5622 cairo_set_line_width(cr, 1);
5623 cairo_move_to(cr, x, y);
5624 cairo_stroke(cr);
5625 if(clip)
5626 cairo_region_destroy(clip);
5627 /* If we are using a drawing context...
5628 * we don't own the cairo context so don't destroy it.
5629 */
5630 if(dc)
5631 gdk_window_end_draw_frame(gtk_widget_get_window(handle), dc);
5632 else
5633 cairo_destroy(cr);
5634 }
5635 }
5636
5637 /* Draw a line on a window (preferably a render window).
5638 * Parameters:
5639 * handle: Handle to the window.
5640 * pixmap: Handle to the pixmap. (choose only one of these)
5641 * x1: First X coordinate.
5642 * y1: First Y coordinate.
5643 * x2: Second X coordinate.
5644 * y2: Second Y coordinate.
5645 */
5646 void dw_draw_line(HWND handle, HPIXMAP pixmap, int x1, int y1, int x2, int y2)
5647 {
5648 cairo_t *cr = NULL;
5649 GdkDrawingContext *dc = NULL;
5650 cairo_region_t *clip = NULL;
5651
5652 if(handle)
5653 {
5654 GdkWindow *window = gtk_widget_get_window(handle);
5655 /* Safety check for non-existant windows */
5656 if(!window || !GDK_IS_WINDOW(window))
5657 return;
5658 clip = gdk_window_get_clip_region(window);
5659 dc = gdk_window_begin_draw_frame(window, clip);
5660 cr = gdk_drawing_context_get_cairo_context(dc);
5661 }
5662 else if(pixmap)
5663 cr = cairo_create(pixmap->image);
5664 if(cr)
5665 {
5666 GdkRGBA *foreground = pthread_getspecific(_dw_fg_color_key);
5667
5668 gdk_cairo_set_source_rgba(cr, foreground);
5669 cairo_set_line_width(cr, 1);
5670 cairo_move_to(cr, x1, y1);
5671 cairo_line_to(cr, x2, y2);
5672 cairo_stroke(cr);
5673 if(clip)
5674 cairo_region_destroy(clip);
5675 /* If we are using a drawing context...
5676 * we don't own the cairo context so don't destroy it.
5677 */
5678 if(dc)
5679 gdk_window_end_draw_frame(gtk_widget_get_window(handle), dc);
5680 else
5681 cairo_destroy(cr);
5682 }
5683 }
5684
5685 /* Draw a closed polygon on a window (preferably a render window).
5686 * Parameters:
5687 * handle: Handle to the window.
5688 * pixmap: Handle to the pixmap. (choose only one of these)
5689 * flags: DW_DRAW_FILL (1) to fill the polygon or DW_DRAW_DEFAULT (0).
5690 * number of points
5691 * x[]: X coordinates.
5692 * y[]: Y coordinates.
5693 */
5694 void dw_draw_polygon(HWND handle, HPIXMAP pixmap, int flags, int npoints, int *x, int *y)
5695 {
5696 cairo_t *cr = NULL;
5697 int z;
5698 GdkDrawingContext *dc = NULL;
5699 cairo_region_t *clip = NULL;
5700
5701 if(handle)
5702 {
5703 GdkWindow *window = gtk_widget_get_window(handle);
5704 /* Safety check for non-existant windows */
5705 if(!window || !GDK_IS_WINDOW(window))
5706 return;
5707 clip = gdk_window_get_clip_region(window);
5708 dc = gdk_window_begin_draw_frame(window, clip);
5709 cr = gdk_drawing_context_get_cairo_context(dc);
5710 }
5711 else if(pixmap)
5712 cr = cairo_create(pixmap->image);
5713 if(cr)
5714 {
5715 GdkRGBA *foreground = pthread_getspecific(_dw_fg_color_key);
5716
5717 if(flags & DW_DRAW_NOAA)
5718 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
5719
5720 gdk_cairo_set_source_rgba(cr, foreground);
5721 cairo_set_line_width(cr, 1);
5722 cairo_move_to(cr, x[0], y[0]);
5723 for(z=1;z<npoints;z++)
5724 {
5725 cairo_line_to(cr, x[z], y[z]);
5726 }
5727 if(flags & DW_DRAW_FILL)
5728 cairo_fill(cr);
5729 cairo_stroke(cr);
5730 if(clip)
5731 cairo_region_destroy(clip);
5732 /* If we are using a drawing context...
5733 * we don't own the cairo context so don't destroy it.
5734 */
5735 if(dc)
5736 gdk_window_end_draw_frame(gtk_widget_get_window(handle), dc);
5737 else
5738 cairo_destroy(cr);
5739 }
5740 }
5741
5742 /* Draw a rectangle on a window (preferably a render window).
5743 * Parameters:
5744 * handle: Handle to the window.
5745 * pixmap: Handle to the pixmap. (choose only one of these)
5746 * flags: DW_DRAW_FILL (1) to fill the box or DW_DRAW_DEFAULT (0).
5747 * x: X coordinate.
5748 * y: Y coordinate.
5749 * width: Width of rectangle.
5750 * height: Height of rectangle.
5751 */
5752 void dw_draw_rect(HWND handle, HPIXMAP pixmap, int flags, int x, int y, int width, int height)
5753 {
5754 cairo_t *cr = NULL;
5755 GdkDrawingContext *dc = NULL;
5756 cairo_region_t *clip = NULL;
5757
5758 if(handle)
5759 {
5760 GdkWindow *window = gtk_widget_get_window(handle);
5761 /* Safety check for non-existant windows */
5762 if(!window || !GDK_IS_WINDOW(window))
5763 return;
5764 clip = gdk_window_get_clip_region(window);
5765 dc = gdk_window_begin_draw_frame(window, clip);
5766 cr = gdk_drawing_context_get_cairo_context(dc);
5767 }
5768 else if(pixmap)
5769 cr = cairo_create(pixmap->image);
5770 if(cr)
5771 {
5772 GdkRGBA *foreground = pthread_getspecific(_dw_fg_color_key);
5773
5774 if(flags & DW_DRAW_NOAA)
5775 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
5776
5777 gdk_cairo_set_source_rgba(cr, foreground);
5778 cairo_set_line_width(cr, 1);
5779 cairo_move_to(cr, x, y);
5780 cairo_line_to(cr, x, y + height);
5781 cairo_line_to(cr, x + width, y + height);
5782 cairo_line_to(cr, x + width, y);
5783 if(flags & DW_DRAW_FILL)
5784 cairo_fill(cr);
5785 cairo_stroke(cr);
5786 if(clip)
5787 cairo_region_destroy(clip);
5788 /* If we are using a drawing context...
5789 * we don't own the cairo context so don't destroy it.
5790 */
5791 if(dc)
5792 gdk_window_end_draw_frame(gtk_widget_get_window(handle), dc);
5793 else
5794 cairo_destroy(cr);
5795 }
5796 }
5797
5798 /* Draw an arc on a window (preferably a render window).
5799 * Parameters:
5800 * handle: Handle to the window.
5801 * pixmap: Handle to the pixmap. (choose only one of these)
5802 * flags: DW_DRAW_FILL (1) to fill the arc or DW_DRAW_DEFAULT (0).
5803 * DW_DRAW_FULL will draw a complete circle/elipse.
5804 * xorigin: X coordinate of center of arc.
5805 * yorigin: Y coordinate of center of arc.
5806 * x1: X coordinate of first segment of arc.
5807 * y1: Y coordinate of first segment of arc.
5808 * x2: X coordinate of second segment of arc.
5809 * y2: Y coordinate of second segment of arc.
5810 */
5811 void API dw_draw_arc(HWND handle, HPIXMAP pixmap, int flags, int xorigin, int yorigin, int x1, int y1, int x2, int y2)
5812 {
5813 cairo_t *cr = NULL;
5814 GdkDrawingContext *dc = NULL;
5815 cairo_region_t *clip = NULL;
5816
5817 if(handle)
5818 {
5819 GdkWindow *window = gtk_widget_get_window(handle);
5820 /* Safety check for non-existant windows */
5821 if(!window || !GDK_IS_WINDOW(window))
5822 return;
5823 clip = gdk_window_get_clip_region(window);
5824 dc = gdk_window_begin_draw_frame(window, clip);
5825 cr = gdk_drawing_context_get_cairo_context(dc);
5826 }
5827 else if(pixmap)
5828 cr = cairo_create(pixmap->image);
5829 if(cr)
5830 {
5831 GdkRGBA *foreground = pthread_getspecific(_dw_fg_color_key);
5832 int width = abs(x2-x1);
5833 float scale = fabs((float)(y2-y1))/(float)width;
5834
5835 if(flags & DW_DRAW_NOAA)
5836 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
5837
5838 gdk_cairo_set_source_rgba(cr, foreground);
5839 cairo_set_line_width(cr, 1);
5840 if(scale != 1.0)
5841 cairo_scale(cr, 1.0, scale);
5842 if(flags & DW_DRAW_FULL)
5843 cairo_arc(cr, xorigin, yorigin / scale, width/2, 0, M_PI*2);
5844 else
5845 {
5846 double dx = xorigin - x1;
5847 double dy = yorigin - y1;
5848 double r = sqrt(dx*dx + dy*dy);
5849 double a1 = atan2((y1-yorigin), (x1-xorigin));
5850 double a2 = atan2((y2-yorigin), (x2-xorigin));
5851
5852 cairo_arc(cr, xorigin, yorigin, r, a1, a2);
5853 }
5854 if(flags & DW_DRAW_FILL)
5855 cairo_fill(cr);
5856 cairo_stroke(cr);
5857 if(clip)
5858 cairo_region_destroy(clip);
5859 /* If we are using a drawing context...
5860 * we don't own the cairo context so don't destroy it.
5861 */
5862 if(dc)
5863 gdk_window_end_draw_frame(gtk_widget_get_window(handle), dc);
5864 else
5865 cairo_destroy(cr);
5866 }
5867 }
5868
5869 /* Draw text on a window (preferably a render window).
5870 * Parameters:
5871 * handle: Handle to the window.
5872 * pixmap: Handle to the pixmap. (choose only one of these)
5873 * x: X coordinate.
5874 * y: Y coordinate.
5875 * text: Text to be displayed.
5876 */
5877 void dw_draw_text(HWND handle, HPIXMAP pixmap, int x, int y, const char *text)
5878 {
5879 cairo_t *cr = NULL;
5880 PangoFontDescription *font;
5881 char *tmpname, *fontname = "monospace 10";
5882 GdkDrawingContext *dc = NULL;
5883 cairo_region_t *clip = NULL;
5884
5885 if(!text)
5886 return;
5887
5888 if(handle)
5889 {
5890 GdkWindow *window = gtk_widget_get_window(handle);
5891 /* Safety check for non-existant windows */
5892 if(!window || !GDK_IS_WINDOW(window))
5893 return;
5894 clip = gdk_window_get_clip_region(window);
5895 dc = gdk_window_begin_draw_frame(window, clip);
5896 cr = gdk_drawing_context_get_cairo_context(dc);
5897 if((tmpname = (char *)g_object_get_data(G_OBJECT(handle), "_dw_fontname")))
5898 fontname = tmpname;
5899 }
5900 else if(pixmap)
5901 {
5902 if(pixmap->font)
5903 fontname = pixmap->font;
5904 else if(pixmap->handle && (tmpname = (char *)g_object_get_data(G_OBJECT(pixmap->handle), "_dw_fontname")))
5905 fontname = tmpname;
5906 cr = cairo_create(pixmap->image);
5907 }
5908 if(cr)
5909 {
5910 font = pango_font_description_from_string(fontname);
5911 if(font)
5912 {
5913 PangoContext *context = pango_cairo_create_context(cr);
5914
5915 if(context)
5916 {
5917 PangoLayout *layout = pango_layout_new(context);
5918
5919 if(layout)
5920 {
5921 GdkRGBA *foreground = pthread_getspecific(_dw_fg_color_key);
5922 GdkRGBA *background = pthread_getspecific(_dw_bg_color_key);
5923
5924 pango_layout_set_font_description(layout, font);
5925 pango_layout_set_text(layout, text, strlen(text));
5926
5927 gdk_cairo_set_source_rgba(cr, foreground);
5928 /* Create a background color attribute if required */
5929 if(background)
5930 {
5931 PangoAttrList *list = pango_layout_get_attributes(layout);
5932 PangoAttribute *attr = pango_attr_background_new((guint16)(background->red * 65535),
5933 (guint16)(background->green * 65535),
5934 (guint16)(background->blue* 65535));
5935 if(!list)
5936 {
5937 list = pango_attr_list_new();
5938 }
5939 pango_attr_list_change(list, attr);
5940 pango_layout_set_attributes(layout, list);
5941 }
5942 /* Do the drawing */
5943 cairo_move_to(cr, x, y);
5944 pango_cairo_show_layout (cr, layout);
5945
5946 g_object_unref(layout);
5947 }
5948 g_object_unref(context);
5949 }
5950 pango_font_description_free(font);
5951 }
5952 if(clip)
5953 cairo_region_destroy(clip);
5954 /* If we are using a drawing context...
5955 * we don't own the cairo context so don't destroy it.
5956 */
5957 if(dc)
5958 gdk_window_end_draw_frame(gtk_widget_get_window(handle), dc);
5959 else
5960 cairo_destroy(cr);
5961 }
5962 }
5963
5964 /* Query the width and height of a text string.
5965 * Parameters:
5966 * handle: Handle to the window.
5967 * pixmap: Handle to the pixmap. (choose only one of these)
5968 * text: Text to be queried.
5969 * width: Pointer to a variable to be filled in with the width.
5970 * height Pointer to a variable to be filled in with the height.
5971 */
5972 void dw_font_text_extents_get(HWND handle, HPIXMAP pixmap, const char *text, int *width, int *height)
5973 {
5974 PangoFontDescription *font;
5975 char *fontname = NULL;
5976 int free_fontname = 0;
5977
5978 if(!text)
5979 return;
5980
5981 if(handle)
5982 {
5983 fontname = (char *)g_object_get_data(G_OBJECT(handle), "_dw_fontname");
5984 if ( fontname == NULL )
5985 {
5986 fontname = dw_window_get_font(handle);
5987 free_fontname = 1;
5988 }
5989 }
5990 else if(pixmap)
5991 {
5992 if(pixmap->font)
5993 fontname = pixmap->font;
5994 else if(pixmap->handle)
5995 fontname = (char *)g_object_get_data(G_OBJECT(pixmap->handle), "_dw_fontname");
5996 }
5997
5998 font = pango_font_description_from_string(fontname ? fontname : "monospace 10");
5999 if(font)
6000 {
6001 PangoContext *context = gdk_pango_context_get();
6002
6003 if(context)
6004 {
6005 PangoLayout *layout = pango_layout_new(context);
6006
6007 if(layout)
6008 {
6009 PangoRectangle rect;
6010
6011 pango_layout_set_font_description(layout, font);
6012 pango_layout_set_text(layout, text, -1);
6013 pango_layout_get_pixel_extents(layout, NULL, &rect);
6014
6015 if(width)
6016 *width = rect.width;
6017 if(height)
6018 *height = rect.height;
6019
6020 g_object_unref(layout);
6021 }
6022 g_object_unref(context);
6023 }
6024 pango_font_description_free(font);
6025 }
6026 if ( free_fontname )
6027 free( fontname );
6028 }
6029
6030 /*
6031 * Creates a pixmap with given parameters.
6032 * Parameters:
6033 * handle: Window handle the pixmap is associated with.
6034 * or zero to enable this pixmap to be written
6035 * off the screen to reduce flicker
6036 * width: Width of the pixmap in pixels.
6037 * height: Height of the pixmap in pixels.
6038 * depth: Color depth of the pixmap.
6039 * Returns:
6040 * A handle to a pixmap or NULL on failure.
6041 */
6042 HPIXMAP dw_pixmap_new(HWND handle, unsigned long width, unsigned long height, int depth)
6043 {
6044 HPIXMAP pixmap;
6045
6046 if (!(pixmap = calloc(1,sizeof(struct _hpixmap))))
6047 return NULL;
6048
6049 if (!depth)
6050 depth = -1;
6051
6052 pixmap->width = width; pixmap->height = height;
6053
6054
6055 pixmap->handle = handle;
6056 /* Depth needs to be divided by 3... but for the RGB colorspace...
6057 * only 8 bits per sample is allowed, so to avoid issues just pass 8 for now.
6058 */
6059 pixmap->pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB, FALSE, 8, width, height );
6060 pixmap->image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
6061 return pixmap;
6062 }
6063
6064 /*
6065 * Creates a pixmap from a file.
6066 * Parameters:
6067 * handle: Window handle the pixmap is associated with.
6068 * filename: Name of the file, omit extention to have
6069 * DW pick the appropriate file extension.
6070 * (BMP on OS/2 or Windows, XPM on Unix)
6071 * Returns:
6072 * A handle to a pixmap or NULL on failure.
6073 */
6074 HPIXMAP dw_pixmap_new_from_file(HWND handle, const char *filename)
6075 {
6076 HPIXMAP pixmap;
6077 char *file = alloca(strlen(filename) + 6);
6078 int found_ext = 0;
6079 int i;
6080
6081 if (!file || !(pixmap = calloc(1,sizeof(struct _hpixmap))))
6082 return NULL;
6083
6084 strcpy(file, filename);
6085
6086 /* check if we can read from this file (it exists and read permission) */
6087 if(access(file, 04) != 0)
6088 {
6089 /* Try with various extentions */
6090 for ( i = 0; i < NUM_EXTS; i++ )
6091 {
6092 strcpy( file, filename );
6093 strcat( file, image_exts[i] );
6094 if ( access( file, 04 ) == 0 )
6095 {
6096 found_ext = 1;
6097 break;
6098 }
6099 }
6100 if ( found_ext == 0 )
6101 {
6102 free(pixmap);
6103 return NULL;
6104 }
6105 }
6106
6107 pixmap->pixbuf = gdk_pixbuf_new_from_file(file, NULL);
6108 pixmap->image = cairo_image_surface_create_from_png(file);
6109 pixmap->width = gdk_pixbuf_get_width(pixmap->pixbuf);
6110 pixmap->height = gdk_pixbuf_get_height(pixmap->pixbuf);
6111 pixmap->handle = handle;
6112 return pixmap;
6113 }
6114
6115 /*
6116 * Creates a pixmap from data
6117 * Parameters:
6118 * handle: Window handle the pixmap is associated with.
6119 * data: Source of image data
6120 * DW pick the appropriate file extension.
6121 * (BMP on OS/2 or Windows, XPM on Unix)
6122 * Returns:
6123 * A handle to a pixmap or NULL on failure.
6124 */
6125 HPIXMAP dw_pixmap_new_from_data(HWND handle, const char *data, int len)
6126 {
6127 int fd, written = -1;
6128 HPIXMAP pixmap;
6129 char template[] = "/tmp/dwpixmapXXXXXX";
6130
6131 if(!data || !(pixmap = calloc(1,sizeof(struct _hpixmap))))
6132 return NULL;
6133
6134 /*
6135 * A real hack; create a temporary file and write the contents
6136 * of the data to the file
6137 */
6138 if((fd = mkstemp(template)) != -1)
6139 {
6140 written = write(fd, data, len);
6141 close(fd);
6142 }
6143 /* Bail if we couldn't write full file */
6144 if(fd == -1 || written != len)
6145 return 0;
6146 pixmap->pixbuf = gdk_pixbuf_new_from_file(template, NULL);
6147 pixmap->image = cairo_image_surface_create_from_png(template);
6148 pixmap->width = gdk_pixbuf_get_width(pixmap->pixbuf);
6149 pixmap->height = gdk_pixbuf_get_height(pixmap->pixbuf);
6150 /* remove our temporary file */
6151 unlink(template);
6152 pixmap->handle = handle;
6153 return pixmap;
6154 }
6155
6156 /*
6157 * Sets the transparent color for a pixmap
6158 * Parameters:
6159 * pixmap: Handle to a pixmap returned by
6160 * dw_pixmap_new..
6161 * color: transparent color
6162 * Note: This does nothing on GTK+ as transparency
6163 * is handled automatically
6164 */
6165 void dw_pixmap_set_transparent_color(HPIXMAP pixmap, unsigned long color)
6166 {
6167 }
6168
6169 /*
6170 * Creates a pixmap from internal resource graphic specified by id.
6171 * Parameters:
6172 * handle: Window handle the pixmap is associated with.
6173 * id: Resource ID associated with requested pixmap.
6174 * Returns:
6175 * A handle to a pixmap or NULL on failure.
6176 */
6177 HPIXMAP dw_pixmap_grab(HWND handle, ULONG id)
6178 {
6179 HPIXMAP pixmap;
6180
6181 if (!(pixmap = calloc(1,sizeof(struct _hpixmap))))
6182 return NULL;
6183
6184 pixmap->pixbuf = gdk_pixbuf_copy(_find_pixbuf((HICN)id, &pixmap->width, &pixmap->height));
6185 return pixmap;
6186 }
6187
6188 /* Call this after drawing to the screen to make sure
6189 * anything you have drawn is visible.
6190 */
6191 void dw_flush(void)
6192 {
6193 }
6194
6195 /*
6196 * Sets the font used by a specified pixmap.
6197 * Normally the pixmap font is obtained from the associated window handle.
6198 * However this can be used to override that, or for pixmaps with no window.
6199 * Parameters:
6200 * pixmap: Handle to a pixmap returned by dw_pixmap_new() or
6201 * passed to the application via a callback.
6202 * fontname: Name and size of the font in the form "size.fontname"
6203 * Returns:
6204 * DW_ERROR_NONE on success and DW_ERROR_GENERAL on failure.
6205 */
6206 int API dw_pixmap_set_font(HPIXMAP pixmap, const char *fontname)
6207 {
6208 if(pixmap)
6209 {
6210 char *oldfont = pixmap->font;
6211
6212 pixmap->font = _convert_font(fontname);
6213
6214 if(oldfont)
6215 free(oldfont);
6216 return DW_ERROR_NONE;
6217 }
6218 return DW_ERROR_GENERAL;
6219 }
6220
6221 /*
6222 * Destroys an allocated pixmap.
6223 * Parameters:
6224 * pixmap: Handle to a pixmap returned by
6225 * dw_pixmap_new..
6226 */
6227 void dw_pixmap_destroy(HPIXMAP pixmap)
6228 {
6229 g_object_unref(G_OBJECT(pixmap->pixbuf));
6230 cairo_surface_destroy(pixmap->image);
6231 if(pixmap->font)
6232 free(pixmap->font);
6233 free(pixmap);
6234 }
6235
6236 /*
6237 * Copies from one item to another.
6238 * Parameters:
6239 * dest: Destination window handle.
6240 * destp: Destination pixmap. (choose only one).
6241 * xdest: X coordinate of destination.
6242 * ydest: Y coordinate of destination.
6243 * width: Width of area to copy.
6244 * height: Height of area to copy.
6245 * src: Source window handle.
6246 * srcp: Source pixmap. (choose only one).
6247 * xsrc: X coordinate of source.
6248 * ysrc: Y coordinate of source.
6249 */
6250 void API dw_pixmap_bitblt(HWND dest, HPIXMAP destp, int xdest, int ydest, int width, int height, HWND src, HPIXMAP srcp, int xsrc, int ysrc)
6251 {
6252 dw_pixmap_stretch_bitblt(dest, destp, xdest, ydest, width, height, src, srcp, xsrc, ysrc, -1, -1);
6253 }
6254
6255 /*
6256 * Copies from one surface to another allowing for stretching.
6257 * Parameters:
6258 * dest: Destination window handle.
6259 * destp: Destination pixmap. (choose only one).
6260 * xdest: X coordinate of destination.
6261 * ydest: Y coordinate of destination.
6262 * width: Width of the target area.
6263 * height: Height of the target area.
6264 * src: Source window handle.
6265 * srcp: Source pixmap. (choose only one).
6266 * xsrc: X coordinate of source.
6267 * ysrc: Y coordinate of source.
6268 * srcwidth: Width of area to copy.
6269 * srcheight: Height of area to copy.
6270 * Returns:
6271 * DW_ERROR_NONE on success and DW_ERROR_GENERAL on failure.
6272 */
6273 int API dw_pixmap_stretch_bitblt(HWND dest, HPIXMAP destp, int xdest, int ydest, int width, int height, HWND src, HPIXMAP srcp, int xsrc, int ysrc, int srcwidth, int srcheight)
6274 {
6275 cairo_t *cr = NULL;
6276 int retval = DW_ERROR_GENERAL;
6277 GdkDrawingContext *dc = NULL;
6278 cairo_region_t *clip = NULL;
6279
6280 if((!dest && (!destp || !destp->image)) || (!src && (!srcp || !srcp->image)))
6281 return retval;
6282
6283 if(dest)
6284 {
6285 GdkWindow *window = gtk_widget_get_window(dest);
6286 /* Safety check for non-existant windows */
6287 if(!window || !GDK_IS_WINDOW(window))
6288 return retval;
6289 clip = gdk_window_get_clip_region(window);
6290 dc = gdk_window_begin_draw_frame(window, clip);
6291 cr = gdk_drawing_context_get_cairo_context(dc);
6292 }
6293 else if(destp)
6294 cr = cairo_create(destp->image);
6295
6296 if(cr)
6297 {
6298 double xscale = 1, yscale = 1;
6299
6300 if(srcwidth != -1 && srcheight != -1)
6301 {
6302 xscale = (double)width / (double)srcwidth;
6303 yscale = (double)height / (double)srcheight;
6304 cairo_scale(cr, xscale, yscale);
6305 }
6306
6307 if(src)
6308 gdk_cairo_set_source_window (cr, gtk_widget_get_window(src), (xdest + xsrc) / xscale, (ydest + ysrc) / yscale);
6309 else if(srcp)
6310 cairo_set_source_surface (cr, srcp->image, (xdest + xsrc) / xscale, (ydest + ysrc) / yscale);
6311
6312 cairo_rectangle(cr, xdest / xscale, ydest / yscale, width, height);
6313 cairo_fill(cr);
6314 if(clip)
6315 cairo_region_destroy(clip);
6316 /* If we are using a drawing context...
6317 * we don't own the cairo context so don't destroy it.
6318 */
6319 if(dc)
6320 gdk_window_end_draw_frame(gtk_widget_get_window(dest), dc);
6321 else
6322 cairo_destroy(cr);
6323 retval = DW_ERROR_NONE;
6324 }
6325 return retval;
6326 }
6327
6328 /*
6329 * Emits a beep.
6330 * Parameters:
6331 * freq: Frequency.
6332 * dur: Duration.
6333 */
6334 void dw_beep(int freq, int dur)
6335 {
6336 gdk_display_beep(gdk_display_get_default());
6337 }
6338
6339 void _my_strlwr(char *buf)
6340 {
6341 int z, len = strlen(buf);
6342
6343 for(z=0;z<len;z++)
6344 {
6345 if(buf[z] >= 'A' && buf[z] <= 'Z')
6346 buf[z] -= 'A' - 'a';
6347 }
6348 }
6349
6350 /* Open a shared library and return a handle.
6351 * Parameters:
6352 * name: Base name of the shared library.
6353 * handle: Pointer to a module handle,
6354 * will be filled in with the handle.
6355 */
6356 int dw_module_load(const char *name, HMOD *handle)
6357 {
6358 int len;
6359 char *newname;
6360 char errorbuf[1025] = {0};
6361
6362
6363 if(!handle)
6364 return -1;
6365
6366 if((len = strlen(name)) == 0)
6367 return -1;
6368
6369 /* Lenth + "lib" + ".so" + NULL */
6370 newname = malloc(len + 7);
6371
6372 if(!newname)
6373 return -1;
6374
6375 sprintf(newname, "lib%s.so", name);
6376 _my_strlwr(newname);
6377
6378 *handle = dlopen(newname, RTLD_NOW);
6379 if(*handle == NULL)
6380 {
6381 strncpy(errorbuf, dlerror(), 1024);
6382 printf("%s\n", errorbuf);
6383 sprintf(newname, "lib%s.so", name);
6384 *handle = dlopen(newname, RTLD_NOW);
6385 }
6386
6387 free(newname);
6388
6389 return (NULL == *handle) ? -1 : 0;
6390 }
6391
6392 /* Queries the address of a symbol within open handle.
6393 * Parameters:
6394 * handle: Module handle returned by dw_module_load()
6395 * name: Name of the symbol you want the address of.
6396 * func: A pointer to a function pointer, to obtain
6397 * the address.
6398 */
6399 int dw_module_symbol(HMOD handle, const char *name, void**func)
6400 {
6401 if(!func || !name)
6402 return -1;
6403
6404 if(strlen(name) == 0)
6405 return -1;
6406
6407 *func = (void*)dlsym(handle, name);
6408 return (NULL == *func);
6409 }
6410
6411 /* Frees the shared library previously opened.
6412 * Parameters:
6413 * handle: Module handle returned by dw_module_load()
6414 */
6415 int dw_module_close(HMOD handle)
6416 {
6417 if(handle)
6418 return dlclose(handle);
6419 return 0;
6420 }
6421
6422 /*
6423 * Returns the handle to an unnamed mutex semaphore.
6424 */
6425 HMTX dw_mutex_new(void)
6426 {
6427 HMTX mutex = malloc(sizeof(pthread_mutex_t));
6428
6429 pthread_mutex_init(mutex, NULL);
6430 return mutex;
6431 }
6432
6433 /*
6434 * Closes a semaphore created by dw_mutex_new().
6435 * Parameters:
6436 * mutex: The handle to the mutex returned by dw_mutex_new().
6437 */
6438 void dw_mutex_close(HMTX mutex)
6439 {
6440 if(mutex)
6441 {
6442 pthread_mutex_destroy(mutex);
6443 free(mutex);
6444 }
6445 }
6446
6447 /*
6448 * Tries to gain access to the semaphore, if it can't it blocks.
6449 * Parameters:
6450 * mutex: The handle to the mutex returned by dw_mutex_new().
6451 */
6452 void dw_mutex_lock(HMTX mutex)
6453 {
6454 /* If we are being called from an event handler we must release
6455 * the GTK mutex so we don't deadlock.
6456 */
6457 if(pthread_self() == _dw_thread)
6458 _dw_gdk_threads_leave();
6459
6460 pthread_mutex_lock(mutex);
6461
6462 /* And of course relock it when we have acquired the mutext */
6463 if(pthread_self() == _dw_thread)
6464 _dw_gdk_threads_enter();
6465 }
6466
6467 /*
6468 * Tries to gain access to the semaphore.
6469 * Parameters:
6470 * mutex: The handle to the mutex returned by dw_mutex_new().
6471 * Returns:
6472 * DW_ERROR_NONE on success, DW_ERROR_TIMEOUT if it is already locked.
6473 */
6474 int API dw_mutex_trylock(HMTX mutex)
6475 {
6476 if(pthread_mutex_trylock(mutex) == 0)
6477 return DW_ERROR_NONE;
6478 return DW_ERROR_TIMEOUT;
6479 }
6480
6481 /*
6482 * Reliquishes the access to the semaphore.
6483 * Parameters:
6484 * mutex: The handle to the mutex returned by dw_mutex_new().
6485 */
6486 void dw_mutex_unlock(HMTX mutex)
6487 {
6488 pthread_mutex_unlock(mutex);
6489 }
6490
6491 /*
6492 * Returns the handle to an unnamed event semaphore.
6493 */
6494 HEV dw_event_new(void)
6495 {
6496 HEV eve = (HEV)malloc(sizeof(struct _dw_unix_event));
6497
6498 if(!eve)
6499 return NULL;
6500
6501 /* We need to be careful here, mutexes on Linux are
6502 * FAST by default but are error checking on other
6503 * systems such as FreeBSD and OS/2, perhaps others.
6504 */
6505 pthread_mutex_init (&(eve->mutex), NULL);
6506 pthread_mutex_lock (&(eve->mutex));
6507 pthread_cond_init (&(eve->event), NULL);
6508
6509 pthread_mutex_unlock (&(eve->mutex));
6510 eve->alive = 1;
6511 eve->posted = 0;
6512
6513 return eve;
6514 }
6515
6516 /*
6517 * Resets a semaphore created by dw_event_new().
6518 * Parameters:
6519 * eve: The handle to the event returned by dw_event_new().
6520 */
6521 int dw_event_reset (HEV eve)
6522 {
6523 if(!eve)
6524 return DW_ERROR_NON_INIT;
6525
6526 pthread_mutex_lock (&(eve->mutex));
6527 pthread_cond_broadcast (&(eve->event));
6528 pthread_cond_init (&(eve->event), NULL);
6529 eve->posted = 0;
6530 pthread_mutex_unlock (&(eve->mutex));
6531 return DW_ERROR_NONE;
6532 }
6533
6534 /*
6535 * Posts a semaphore created by dw_event_new(). Causing all threads
6536 * waiting on this event in dw_event_wait to continue.
6537 * Parameters:
6538 * eve: The handle to the event returned by dw_event_new().
6539 */
6540 int dw_event_post (HEV eve)
6541 {
6542 if(!eve)
6543 return DW_ERROR_NON_INIT;
6544
6545 pthread_mutex_lock (&(eve->mutex));
6546 pthread_cond_broadcast (&(eve->event));
6547 eve->posted = 1;
6548 pthread_mutex_unlock (&(eve->mutex));
6549 return DW_ERROR_NONE;
6550 }
6551
6552 /*
6553 * Waits on a semaphore created by dw_event_new(), until the
6554 * event gets posted or until the timeout expires.
6555 * Parameters:
6556 * eve: The handle to the event returned by dw_event_new().
6557 */
6558 int dw_event_wait(HEV eve, unsigned long timeout)
6559 {
6560 int rc;
6561
6562 if(!eve)
6563 return DW_ERROR_NON_INIT;
6564
6565 pthread_mutex_lock (&(eve->mutex));
6566
6567 if(eve->posted)
6568 {
6569 pthread_mutex_unlock (&(eve->mutex));
6570 return DW_ERROR_NONE;
6571 }
6572
6573 if(timeout != -1)
6574 {
6575 struct timeval now;
6576 struct timespec timeo;
6577
6578 gettimeofday(&now, 0);
6579 timeo.tv_sec = now.tv_sec + (timeout / 1000);
6580 timeo.tv_nsec = now.tv_usec * 1000;
6581 rc = pthread_cond_timedwait(&(eve->event), &(eve->mutex), &timeo);
6582 }
6583 else
6584 rc = pthread_cond_wait(&(eve->event), &(eve->mutex));
6585
6586 pthread_mutex_unlock (&(eve->mutex));
6587 if(!rc)
6588 return DW_ERROR_NONE;
6589 if(rc == ETIMEDOUT)
6590 return DW_ERROR_TIMEOUT;
6591 return DW_ERROR_GENERAL;
6592 }
6593
6594 /*
6595 * Closes a semaphore created by dw_event_new().
6596 * Parameters:
6597 * eve: The handle to the event returned by dw_event_new().
6598 */
6599 int dw_event_close(HEV *eve)
6600 {
6601 if(!eve || !(*eve))
6602 return DW_ERROR_NON_INIT;
6603
6604 pthread_mutex_lock (&((*eve)->mutex));
6605 pthread_cond_destroy (&((*eve)->event));
6606 pthread_mutex_unlock (&((*eve)->mutex));
6607 pthread_mutex_destroy (&((*eve)->mutex));
6608 free(*eve);
6609 *eve = NULL;
6610
6611 return DW_ERROR_NONE;
6612 }
6613
6614 struct _seminfo {
6615 int fd;
6616 int waiting;
6617 };
6618
6619 static void _handle_sem(int *tmpsock)
6620 {
6621 fd_set rd;
6622 struct _seminfo *array = (struct _seminfo *)malloc(sizeof(struct _seminfo));
6623 int listenfd = tmpsock[0];
6624 int bytesread, connectcount = 1, maxfd, z, posted = 0;
6625 char command;
6626 sigset_t mask;
6627
6628 sigfillset(&mask); /* Mask all allowed signals */
6629 pthread_sigmask(SIG_BLOCK, &mask, NULL);
6630
6631 /* problems */
6632 if(tmpsock[1] == -1)
6633 {
6634 free(array);
6635 return;
6636 }
6637
6638 array[0].fd = tmpsock[1];
6639 array[0].waiting = 0;
6640
6641 /* Free the memory allocated in dw_named_event_new. */
6642 free(tmpsock);
6643
6644 while(1)
6645 {
6646 FD_ZERO(&rd);
6647 FD_SET(listenfd, &rd);
6648 int DW_UNUSED(result);
6649
6650 maxfd = listenfd;
6651
6652 /* Added any connections to the named event semaphore */
6653 for(z=0;z<connectcount;z++)
6654 {
6655 if(array[z].fd > maxfd)
6656 maxfd = array[z].fd;
6657
6658 FD_SET(array[z].fd, &rd);
6659 }
6660
6661 if(select(maxfd+1, &rd, NULL, NULL, NULL) == -1)
6662 {
6663 free(array);
6664 return;
6665 }
6666
6667 if(FD_ISSET(listenfd, &rd))
6668 {
6669 struct _seminfo *newarray;
6670 int newfd = accept(listenfd, 0, 0);
6671
6672 if(newfd > -1)
6673 {
6674 /* Add new connections to the set */
6675 newarray = (struct _seminfo *)malloc(sizeof(struct _seminfo)*(connectcount+1));
6676 memcpy(newarray, array, sizeof(struct _seminfo)*(connectcount));
6677
6678 newarray[connectcount].fd = newfd;
6679 newarray[connectcount].waiting = 0;
6680
6681 connectcount++;
6682
6683 /* Replace old array with new one */
6684 free(array);
6685 array = newarray;
6686 }
6687 }
6688
6689 /* Handle any events posted to the semaphore */
6690 for(z=0;z<connectcount;z++)
6691 {
6692 if(FD_ISSET(array[z].fd, &rd))
6693 {
6694 if((bytesread = read(array[z].fd, &command, 1)) < 1)
6695 {
6696 struct _seminfo *newarray;
6697
6698 /* Remove this connection from the set */
6699 newarray = (struct _seminfo *)malloc(sizeof(struct _seminfo)*(connectcount-1));
6700 if(!z)
6701 memcpy(newarray, &array[1], sizeof(struct _seminfo)*(connectcount-1));
6702 else
6703 {
6704 memcpy(newarray, array, sizeof(struct _seminfo)*z);
6705 if(z!=(connectcount-1))
6706 memcpy(&newarray[z], &array[z+1], sizeof(struct _seminfo)*(z-connectcount-1));
6707 }
6708 connectcount--;
6709
6710 /* Replace old array with new one */
6711 free(array);
6712 array = newarray;
6713 }
6714 else if(bytesread == 1)
6715 {
6716 switch(command)
6717 {
6718 case 0:
6719 {
6720 /* Reset */
6721 posted = 0;
6722 }
6723 break;
6724 case 1:
6725 /* Post */
6726 {
6727 int s;
6728 char tmp = (char)0;
6729
6730 posted = 1;
6731
6732 for(s=0;s<connectcount;s++)
6733 {
6734 /* The semaphore has been posted so
6735 * we tell all the waiting threads to
6736 * continue.
6737 */
6738 if(array[s].waiting)
6739 result = write(array[s].fd, &tmp, 1);
6740 }
6741 }
6742 break;
6743 case 2:
6744 /* Wait */
6745 {
6746 char tmp = (char)0;
6747
6748 array[z].waiting = 1;
6749
6750 /* If we are posted exit immeditately */
6751 if(posted)
6752 result = write(array[z].fd, &tmp, 1);
6753 }
6754 break;
6755 case 3:
6756 {
6757 /* Done Waiting */
6758 array[z].waiting = 0;
6759 }
6760 break;
6761 }
6762 }
6763 }
6764 }
6765 }
6766 }
6767
6768 /* Using domain sockets on unix for IPC */
6769 /* Create a named event semaphore which can be
6770 * opened from other processes.
6771 * Parameters:
6772 * eve: Pointer to an event handle to receive handle.
6773 * name: Name given to semaphore which can be opened
6774 * by other processes.
6775 */
6776 HEV dw_named_event_new(const char *name)
6777 {
6778 struct sockaddr_un un;
6779 int ev, *tmpsock = (int *)malloc(sizeof(int)*2);
6780 DWTID dwthread;
6781
6782 if(!tmpsock)
6783 return NULL;
6784
6785 tmpsock[0] = socket(AF_UNIX, SOCK_STREAM, 0);
6786 ev = socket(AF_UNIX, SOCK_STREAM, 0);
6787 memset(&un, 0, sizeof(un));
6788 un.sun_family=AF_UNIX;
6789 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH);
6790 strcpy(un.sun_path, "/tmp/.dw/");
6791 strcat(un.sun_path, name);
6792
6793 /* just to be safe, this should be changed
6794 * to support multiple instances.
6795 */
6796 remove(un.sun_path);
6797
6798 bind(tmpsock[0], (struct sockaddr *)&un, sizeof(un));
6799 listen(tmpsock[0], 0);
6800 connect(ev, (struct sockaddr *)&un, sizeof(un));
6801 tmpsock[1] = accept(tmpsock[0], 0, 0);
6802
6803 if(tmpsock[0] < 0 || tmpsock[1] < 0 || ev < 0)
6804 {
6805 if(tmpsock[0] > -1)
6806 close(tmpsock[0]);
6807 if(tmpsock[1] > -1)
6808 close(tmpsock[1]);
6809 if(ev > -1)
6810 close(ev);
6811 free(tmpsock);
6812 return NULL;
6813 }
6814
6815 /* Create a thread to handle this event semaphore */
6816 pthread_create(&dwthread, NULL, (void *)_handle_sem, (void *)tmpsock);
6817 return GINT_TO_POINTER(ev);
6818 }
6819
6820 /* Open an already existing named event semaphore.
6821 * Parameters:
6822 * eve: Pointer to an event handle to receive handle.
6823 * name: Name given to semaphore which can be opened
6824 * by other processes.
6825 */
6826 HEV dw_named_event_get(const char *name)
6827 {
6828 struct sockaddr_un un;
6829 int ev = socket(AF_UNIX, SOCK_STREAM, 0);
6830 if(ev < 0)
6831 return NULL;
6832
6833 un.sun_family=AF_UNIX;
6834 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH);
6835 strcpy(un.sun_path, "/tmp/.dw/");
6836 strcat(un.sun_path, name);
6837 connect(ev, (struct sockaddr *)&un, sizeof(un));
6838 return GINT_TO_POINTER(ev);
6839 }
6840
6841 /* Resets the event semaphore so threads who call wait
6842 * on this semaphore will block.
6843 * Parameters:
6844 * eve: Handle to the semaphore obtained by
6845 * an open or create call.
6846 */
6847 int dw_named_event_reset(HEV eve)
6848 {
6849 /* signal reset */
6850 char tmp = (char)0;
6851
6852 if(GPOINTER_TO_INT(eve) < 0)
6853 return DW_ERROR_NONE;
6854
6855 if(write(GPOINTER_TO_INT(eve), &tmp, 1) == 1)
6856 return DW_ERROR_NONE;
6857 return DW_ERROR_GENERAL;
6858 }
6859
6860 /* Sets the posted state of an event semaphore, any threads
6861 * waiting on the semaphore will no longer block.
6862 * Parameters:
6863 * eve: Handle to the semaphore obtained by
6864 * an open or create call.
6865 */
6866 int dw_named_event_post(HEV eve)
6867 {
6868
6869 /* signal post */
6870 char tmp = (char)1;
6871
6872 if(GPOINTER_TO_INT(eve) < 0)
6873 return DW_ERROR_NONE;
6874
6875 if(write(GPOINTER_TO_INT(eve), &tmp, 1) == 1)
6876 return DW_ERROR_NONE;
6877 return DW_ERROR_GENERAL;
6878 }
6879
6880 /* Waits on the specified semaphore until it becomes
6881 * posted, or returns immediately if it already is posted.
6882 * Parameters:
6883 * eve: Handle to the semaphore obtained by
6884 * an open or create call.
6885 * timeout: Number of milliseconds before timing out
6886 * or -1 if indefinite.
6887 */
6888 int dw_named_event_wait(HEV eve, unsigned long timeout)
6889 {
6890 fd_set rd;
6891 struct timeval tv, *useme = NULL;
6892 int retval = 0;
6893 char tmp;
6894
6895 if(GPOINTER_TO_INT(eve) < 0)
6896 return DW_ERROR_NON_INIT;
6897
6898 /* Set the timout or infinite */
6899 if(timeout != -1)
6900 {
6901 tv.tv_sec = timeout / 1000;
6902 tv.tv_usec = timeout % 1000;
6903
6904 useme = &tv;
6905 }
6906
6907 FD_ZERO(&rd);
6908 FD_SET(GPOINTER_TO_INT(eve), &rd);
6909
6910 /* Signal wait */
6911 tmp = (char)2;
6912 retval = write(GPOINTER_TO_INT(eve), &tmp, 1);
6913
6914 if(retval == 1)
6915 retval = select(GPOINTER_TO_INT(eve)+1, &rd, NULL, NULL, useme);
6916
6917 /* Signal done waiting. */
6918 tmp = (char)3;
6919 if(retval == 1)
6920 retval = write(GPOINTER_TO_INT(eve), &tmp, 1);
6921
6922 if(retval == 0)
6923 return DW_ERROR_TIMEOUT;
6924 else if(retval == -1)
6925 return DW_ERROR_INTERRUPT;
6926
6927 /* Clear the entry from the pipe so
6928 * we don't loop endlessly. :)
6929 */
6930 if(read(GPOINTER_TO_INT(eve), &tmp, 1) == 1)
6931 return DW_ERROR_NONE;
6932 return DW_ERROR_GENERAL;
6933 }
6934
6935 /* Release this semaphore, if there are no more open
6936 * handles on this semaphore the semaphore will be destroyed.
6937 * Parameters:
6938 * eve: Handle to the semaphore obtained by
6939 * an open or create call.
6940 */
6941 int dw_named_event_close(HEV eve)
6942 {
6943 /* Finally close the domain socket,
6944 * cleanup will continue in _handle_sem.
6945 */
6946 close(GPOINTER_TO_INT(eve));
6947 return DW_ERROR_NONE;
6948 }
6949
6950 /*
6951 * Generally an internal function called from a newly created
6952 * thread to setup the Dynamic Windows environment for the thread.
6953 * However it is exported so language bindings can call it when
6954 * they create threads that require access to Dynamic Windows.
6955 */
6956 void API _dw_init_thread(void)
6957 {
6958 GdkRGBA *foreground = malloc(sizeof(GdkRGBA));
6959
6960 foreground->alpha = foreground->red = foreground->green = foreground->blue = 0.0;
6961 pthread_setspecific(_dw_fg_color_key, foreground);
6962 pthread_setspecific(_dw_bg_color_key, NULL);
6963 }
6964
6965 /*
6966 * Generally an internal function called from a terminating
6967 * thread to cleanup the Dynamic Windows environment for the thread.
6968 * However it is exported so language bindings can call it when
6969 * they exit threads that require access to Dynamic Windows.
6970 */
6971 void API _dw_deinit_thread(void)
6972 {
6973 GdkRGBA *foreground, *background;
6974
6975 if((foreground = pthread_getspecific(_dw_fg_color_key)))
6976 free(foreground);
6977 if((background = pthread_getspecific(_dw_bg_color_key)))
6978 free(background);
6979 }
6980
6981 /*
6982 * Setup thread independent color sets.
6983 */
6984 void _dwthreadstart(void *data)
6985 {
6986 void (*threadfunc)(void *) = NULL;
6987 void **tmp = (void **)data;
6988
6989 threadfunc = (void (*)(void *))tmp[0];
6990
6991 /* Initialize colors */
6992 _dw_init_thread();
6993
6994 threadfunc(tmp[1]);
6995 free(tmp);
6996
6997 /* Free colors */
6998 _dw_deinit_thread();
6999 }
7000
7001 /*
7002 * Allocates a shared memory region with a name.
7003 * Parameters:
7004 * handle: A pointer to receive a SHM identifier.
7005 * dest: A pointer to a pointer to receive the memory address.
7006 * size: Size in bytes of the shared memory region to allocate.
7007 * name: A string pointer to a unique memory name.
7008 */
7009 HSHM dw_named_memory_new(void **dest, int size, const char *name)
7010 {
7011 char namebuf[1025];
7012 struct _dw_unix_shm *handle = malloc(sizeof(struct _dw_unix_shm));
7013
7014 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH);
7015 snprintf(namebuf, 1024, "/tmp/.dw/%s", name);
7016
7017 if((handle->fd = open(namebuf, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0)
7018 {
7019 free(handle);
7020 return NULL;
7021 }
7022
7023 if(ftruncate(handle->fd, size))
7024 {
7025 close(handle->fd);
7026 free(handle);
7027 return NULL;
7028 }
7029
7030 /* attach the shared memory segment to our process's address space. */
7031 *dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0);
7032
7033 if(*dest == MAP_FAILED)
7034 {
7035 close(handle->fd);
7036 *dest = NULL;
7037 free(handle);
7038 return NULL;
7039 }
7040
7041 handle->size = size;
7042 handle->sid = getsid(0);
7043 handle->path = strdup(namebuf);
7044
7045 return handle;
7046 }
7047
7048 /*
7049 * Aquires shared memory region with a name.
7050 * Parameters:
7051 * dest: A pointer to a pointer to receive the memory address.
7052 * size: Size in bytes of the shared memory region to requested.
7053 * name: A string pointer to a unique memory name.
7054 */
7055 HSHM dw_named_memory_get(void **dest, int size, const char *name)
7056 {
7057 char namebuf[1025];
7058 struct _dw_unix_shm *handle = malloc(sizeof(struct _dw_unix_shm));
7059
7060 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH);
7061 snprintf(namebuf, 1024, "/tmp/.dw/%s", name);
7062
7063 if((handle->fd = open(namebuf, O_RDWR)) < 0)
7064 {
7065 free(handle);
7066 return NULL;
7067 }
7068
7069 /* attach the shared memory segment to our process's address space. */
7070 *dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0);
7071
7072 if(*dest == MAP_FAILED)
7073 {
7074 close(handle->fd);
7075 *dest = NULL;
7076 free(handle);
7077 return NULL;
7078 }
7079
7080 handle->size = size;
7081 handle->sid = -1;
7082 handle->path = NULL;
7083
7084 return handle;
7085 }
7086
7087 /*
7088 * Frees a shared memory region previously allocated.
7089 * Parameters:
7090 * handle: Handle obtained from DB_named_memory_allocate.
7091 * ptr: The memory address aquired with DB_named_memory_allocate.
7092 */
7093 int dw_named_memory_free(HSHM handle, void *ptr)
7094 {
7095 struct _dw_unix_shm *h = handle;
7096 int rc = munmap(ptr, h->size);
7097
7098 close(h->fd);
7099 if(h->path)
7100 {
7101 /* Only remove the actual file if we are the
7102 * creator of the file.
7103 */
7104 if(h->sid != -1 && h->sid == getsid(0))
7105 remove(h->path);
7106 free(h->path);
7107 }
7108 return rc;
7109 }
7110 /*
7111 * Creates a new thread with a starting point of func.
7112 * Parameters:
7113 * func: Function which will be run in the new thread.
7114 * data: Parameter(s) passed to the function.
7115 * stack: Stack size of new thread (OS/2 and Windows only).
7116 */
7117 DWTID dw_thread_new(void *func, void *data, int stack)
7118 {
7119 DWTID gtkthread;
7120 void **tmp = malloc(sizeof(void *) * 2);
7121 int rc;
7122
7123 tmp[0] = func;
7124 tmp[1] = data;
7125
7126 rc = pthread_create(&gtkthread, NULL, (void *)_dwthreadstart, (void *)tmp);
7127 if ( rc == 0 )
7128 return gtkthread;
7129 return (DWTID)DW_ERROR_UNKNOWN;
7130 }
7131
7132 /*
7133 * Ends execution of current thread immediately.
7134 */
7135 void dw_thread_end(void)
7136 {
7137 pthread_exit(NULL);
7138 }
7139
7140 /*
7141 * Returns the current thread's ID.
7142 */
7143 DWTID dw_thread_id(void)
7144 {
7145 return (DWTID)pthread_self();
7146 }
7147
7148 /*
7149 * Cleanly terminates a DW session, should be signal handler safe.
7150 */
7151 void dw_shutdown(void)
7152 {
7153 }
7154
7155 /*
7156 * Cleanly terminates a DW session, should be signal handler safe.
7157 * Parameters:
7158 * exitcode: Exit code reported to the operating system.
7159 */
7160 void dw_exit(int exitcode)
7161 {
7162 exit(exitcode);
7163 }
7164
7165 /* Internal function to get the recommended size of scrolled items */
7166 void _get_scrolled_size(GtkWidget *item, gint *thiswidth, gint *thisheight)
7167 {
7168 GtkWidget *widget = g_object_get_data(G_OBJECT(item), "_dw_user");
7169
7170 *thisheight = *thiswidth = 0;
7171
7172 if(widget)
7173 {
7174 if(g_object_get_data(G_OBJECT(widget), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_TREE))
7175 {
7176 /* Set to half for tree */
7177 *thiswidth = (int)((_DW_SCROLLED_MAX_WIDTH + _DW_SCROLLED_MIN_WIDTH)/2);
7178 *thisheight = (int)((_DW_SCROLLED_MAX_HEIGHT + _DW_SCROLLED_MIN_HEIGHT)/2);
7179 }
7180 else if(GTK_IS_TEXT_VIEW(widget))
7181 {
7182 unsigned long bytes;
7183 int height, width;
7184 char *buf, *ptr;
7185 int wrap = (gtk_text_view_get_wrap_mode(GTK_TEXT_VIEW(widget)) == GTK_WRAP_WORD);
7186 static char testtext[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
7187 int hscrolled = FALSE;
7188
7189 *thiswidth = *thisheight = 0;
7190
7191 dw_mle_get_size(item, &bytes, NULL);
7192
7193 ptr = buf = alloca(bytes + 2);
7194 dw_mle_export(item, buf, 0, (int)bytes);
7195 buf[bytes] = 0;
7196 strcat(buf, "\r");
7197
7198 /* MLE */
7199 while((ptr = strstr(buf, "\r")))
7200 {
7201 ptr[0] = 0;
7202 width = 0;
7203 if(strlen(buf))
7204 dw_font_text_extents_get(item, NULL, buf, &width, &height);
7205 else
7206 dw_font_text_extents_get(item, NULL, testtext, NULL, &height);
7207
7208 if(wrap && width > _DW_SCROLLED_MAX_WIDTH)
7209 {
7210 *thiswidth = _DW_SCROLLED_MAX_WIDTH;
7211 *thisheight += height * (width / _DW_SCROLLED_MAX_WIDTH);
7212 }
7213 else
7214 {
7215 if(width > *thiswidth)
7216 {
7217 if(width > _DW_SCROLLED_MAX_WIDTH)
7218 {
7219 *thiswidth = _DW_SCROLLED_MAX_WIDTH;
7220 hscrolled = TRUE;
7221 }
7222 else
7223 *thiswidth = width;
7224 }
7225 }
7226 *thisheight += height;
7227 if(ptr[1] == '\n')
7228 buf = &ptr[2];
7229 else
7230 buf = &ptr[1];
7231 }
7232 if(hscrolled)
7233 *thisheight += 10;
7234 }
7235 else
7236 {
7237 gtk_widget_get_preferred_height(GTK_WIDGET(widget), NULL, thisheight);
7238 gtk_widget_get_preferred_width(GTK_WIDGET(widget), NULL, thiswidth);
7239
7240 *thisheight += 20;
7241 *thiswidth += 20;
7242 }
7243 }
7244 if(*thiswidth < _DW_SCROLLED_MIN_WIDTH)
7245 *thiswidth = _DW_SCROLLED_MIN_WIDTH;
7246 if(*thiswidth > _DW_SCROLLED_MAX_WIDTH)
7247 *thiswidth = _DW_SCROLLED_MAX_WIDTH;
7248 if(*thisheight < _DW_SCROLLED_MIN_HEIGHT)
7249 *thisheight = _DW_SCROLLED_MIN_HEIGHT;
7250 if(*thisheight > _DW_SCROLLED_MAX_HEIGHT)
7251 *thisheight = _DW_SCROLLED_MAX_HEIGHT;
7252 }
7253
7254 /* Internal box packing function called by the other 3 functions */
7255 void _dw_box_pack(HWND box, HWND item, int index, int width, int height, int hsize, int vsize, int pad, char *funcname)
7256 {
7257 int warn = FALSE;
7258 GtkWidget *tmp, *tmpitem, *image = NULL;
7259
7260 if(!box)
7261 return;
7262
7263 /*
7264 * If you try and pack an item into itself VERY bad things can happen; like at least an
7265 * infinite loop on GTK! Lets be safe!
7266 */
7267 if(box == item)
7268 {
7269 dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Danger! Danger! Will Robinson; box and item are the same!");
7270 return;
7271 }
7272
7273 /* If this is a special box, like: Window, Groupbox, Scrollbox...
7274 * get the internal box handle.
7275 */
7276 if((tmp = g_object_get_data(G_OBJECT(box), "_dw_boxhandle")))
7277 box = tmp;
7278
7279 /* Can't pack nothing with GTK, so create an empty label */
7280 if(!item)
7281 {
7282 item = gtk_label_new("");
7283 g_object_set_data(G_OBJECT(item), "_dw_padding", GINT_TO_POINTER(1));
7284 gtk_widget_show_all(item);
7285 }
7286 /* Due to GTK3 minimum size limitations, if we are packing a widget
7287 * with an image, we need to scale the image down to fit the packed size.
7288 */
7289 else if((image = g_object_get_data(G_OBJECT(item), "_dw_bitmap")))
7290 {
7291 GdkPixbuf *pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(image));
7292
7293 if(pixbuf)
7294 {
7295 int pwidth = gdk_pixbuf_get_width(pixbuf);
7296 int pheight = gdk_pixbuf_get_height(pixbuf);
7297
7298 if(width == -1)
7299 width = pwidth;
7300 if(height == -1)
7301 height = pheight;
7302
7303 if(pwidth > width || pheight > height)
7304 pixbuf = gdk_pixbuf_scale_simple(pixbuf, pwidth > width ? width : pwidth, pheight > height ? height : pheight, GDK_INTERP_BILINEAR);
7305 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
7306 }
7307 }
7308
7309 /* Check if the item to be packed is a special box */
7310 tmpitem = (GtkWidget *)g_object_get_data(G_OBJECT(item), "_dw_boxhandle");
7311
7312 /* Make sure our target box is valid */
7313 if(GTK_IS_GRID(box))
7314 {
7315 int boxcount = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(box), "_dw_boxcount"));
7316 int boxtype = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(box), "_dw_boxtype"));
7317
7318 /* If the item being packed is a box, then we use it's padding
7319 * instead of the padding specified on the pack line, this is
7320 * due to a bug in the OS/2 and Win32 renderer and a limitation
7321 * of the GtkTable class.
7322 */
7323 if(GTK_IS_GRID(item) || (tmpitem && GTK_IS_GRID(tmpitem)))
7324 {
7325 GtkWidget *eventbox = (GtkWidget *)g_object_get_data(G_OBJECT(item), "_dw_eventbox");
7326
7327 /* NOTE: I left in the ability to pack boxes with a size,
7328 * this eliminates that by forcing the size to 0.
7329 */
7330 height = width = 0;
7331
7332 if(eventbox)
7333 {
7334 int boxpad = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "_dw_boxpad"));
7335 gtk_container_add(GTK_CONTAINER(eventbox), item);
7336 gtk_container_set_border_width(GTK_CONTAINER(eventbox), boxpad);
7337 item = eventbox;
7338 }
7339 }
7340 else
7341 {
7342 /* Only show warning if item is not a box */
7343 warn = TRUE;
7344 }
7345
7346 /* Do some sanity bounds checking */
7347 if(index < 0)
7348 index = 0;
7349 if(index > boxcount)
7350 index = boxcount;
7351
7352 g_object_set_data(G_OBJECT(item), "_dw_table", box);
7353 /* Set the expand attribute on the widgets now instead of the container */
7354 gtk_widget_set_vexpand(item, vsize);
7355 gtk_widget_set_valign(item, vsize ? GTK_ALIGN_FILL : GTK_ALIGN_START);
7356 gtk_widget_set_hexpand(item, hsize);
7357 gtk_widget_set_halign(item, hsize ? GTK_ALIGN_FILL : GTK_ALIGN_START);
7358 /* Use the margin property as padding */
7359 g_object_set(G_OBJECT(item), "margin", pad, NULL);
7360 /* Add to the grid using insert...
7361 * rows for vertical boxes and columns for horizontal.
7362 */
7363 if(boxtype == DW_VERT)
7364 {
7365 gtk_grid_insert_row(GTK_GRID(box), index);
7366 gtk_grid_attach(GTK_GRID(box), item, 0, index, 1, 1);
7367 }
7368 else
7369 {
7370 gtk_grid_insert_column(GTK_GRID(box), index);
7371 gtk_grid_attach(GTK_GRID(box), item, index, 0, 1, 1);
7372 }
7373 g_object_set_data(G_OBJECT(box), "_dw_boxcount", GINT_TO_POINTER(boxcount + 1));
7374 /* Special case for scrolled windows */
7375 if(GTK_IS_SCROLLED_WINDOW(item))
7376 {
7377 gint scrolledwidth = 0, scrolledheight = 0;
7378
7379 /* Pre-run the calculation code for MLE/Container/Tree if needed */
7380 if((width < 1 && !hsize) || (height < 1 && !vsize))
7381 _get_scrolled_size(item, &scrolledwidth, &scrolledheight);
7382
7383 if(width > 0)
7384 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(item), width);
7385 else if(!hsize)
7386 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(item), scrolledwidth);
7387 if(height > 0)
7388 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(item), height);
7389 else if(!vsize)
7390 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(item), scrolledheight);
7391 }
7392 else
7393 {
7394 /* Set the requested size of the widget */
7395 if(width == -1 && (GTK_IS_COMBO_BOX(item) || GTK_IS_ENTRY(item)))
7396 gtk_widget_set_size_request(item, 150, height);
7397 else if(width == -1 && GTK_IS_SPIN_BUTTON(item))
7398 gtk_widget_set_size_request(item, 50, height);
7399 else
7400 gtk_widget_set_size_request(item, width, height);
7401 }
7402 if(GTK_IS_RADIO_BUTTON(item))
7403 {
7404 GSList *group;
7405 GtkWidget *groupstart = (GtkWidget *)g_object_get_data(G_OBJECT(box), "_dw_group");
7406
7407 if(groupstart)
7408 {
7409 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(groupstart));
7410 gtk_radio_button_set_group(GTK_RADIO_BUTTON(item), group);
7411 }
7412 else
7413 g_object_set_data(G_OBJECT(box), "_dw_group", (gpointer)item);
7414 }
7415 /* If we previously incremented the reference count... drop it now that it is packed */
7416 if(g_object_get_data(G_OBJECT(item), "_dw_refed"))
7417 {
7418 g_object_unref(G_OBJECT(item));
7419 g_object_set_data(G_OBJECT(item), "_dw_refed", NULL);
7420 }
7421 }
7422
7423 if(warn)
7424 {
7425 if ( width == 0 && hsize == FALSE )
7426 dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Width and expand Horizonal both unset for box: %x item: %x",box,item);
7427 if ( height == 0 && vsize == FALSE )
7428 dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Height and expand Vertical both unset for box: %x item: %x",box,item);
7429 }
7430 }
7431
7432 /*
7433 * Remove windows (widgets) from the box they are packed into.
7434 * Parameters:
7435 * handle: Window handle of the packed item to be removed.
7436 * Returns:
7437 * DW_ERROR_NONE on success and DW_ERROR_GENERAL on failure.
7438 */
7439 int API dw_box_unpack(HWND handle)
7440 {
7441 int retcode = DW_ERROR_GENERAL;
7442
7443 if(GTK_IS_WIDGET(handle))
7444 {
7445 GtkWidget *box, *handle2 = handle;
7446 GtkWidget *eventbox = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_eventbox");
7447
7448 /* Handle the invisible event box if it exists */
7449 if(eventbox && GTK_IS_WIDGET(eventbox))
7450 handle2 = eventbox;
7451
7452 /* Check if we are removing a widget from a box */
7453 if((box = gtk_widget_get_parent(handle2)) && GTK_IS_GRID(box))
7454 {
7455 /* Get the number of items in the box... */
7456 int boxcount = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(box), "_dw_boxcount"));
7457 int boxtype = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(box), "_dw_boxtype"));
7458
7459 if(boxcount > 0)
7460 {
7461 /* Decrease the count by 1 */
7462 boxcount--;
7463 g_object_set_data(G_OBJECT(box), "_dw_boxcount", GINT_TO_POINTER(boxcount));
7464 }
7465 /* If we haven't incremented the reference count... raise it before removal */
7466 if(!g_object_get_data(G_OBJECT(handle2), "_dw_refed"))
7467 {
7468 g_object_ref(G_OBJECT(handle2));
7469 g_object_set_data(G_OBJECT(handle2), "_dw_refed", GINT_TO_POINTER(1));
7470 }
7471 /* Remove the widget from the box */
7472 /* Figure out where in the grid this widget is and remove that row/column */
7473 if(boxtype == DW_VERT)
7474 {
7475 int z;
7476
7477 for(z=0;z<boxcount;z++)
7478 {
7479 if(gtk_grid_get_child_at(GTK_GRID(box), 0, z) == handle2)
7480 {
7481 gtk_grid_remove_row(GTK_GRID(box), z);
7482 break;
7483 }
7484 }
7485 }
7486 else
7487 {
7488 int z;
7489
7490 for(z=0;z<boxcount;z++)
7491 {
7492 if(gtk_grid_get_child_at(GTK_GRID(box), z, 0) == handle2)
7493 {
7494 gtk_grid_remove_column(GTK_GRID(box), z);
7495 break;
7496 }
7497 }
7498 }
7499 retcode = DW_ERROR_NONE;
7500 }
7501 }
7502 return retcode;
7503 }
7504
7505 /*
7506 * Remove windows (widgets) from a box at an arbitrary location.
7507 * Parameters:
7508 * box: Window handle of the box to be removed from.
7509 * index: 0 based index of packed items.
7510 * Returns:
7511 * Handle to the removed item on success, 0 on failure or padding.
7512 */
7513 HWND API dw_box_unpack_at_index(HWND box, int index)
7514 {
7515 HWND retval = 0;
7516
7517 /* Check if we are removing a widget from a box */
7518 if(GTK_IS_GRID(box))
7519 {
7520 /* Get the number of items in the box... */
7521 int boxcount = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(box), "_dw_boxcount"));
7522 int boxtype = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(box), "_dw_boxtype"));
7523 GtkWidget *item = (boxtype == DW_VERT) ? gtk_grid_get_child_at(GTK_GRID(box), 0, index) : gtk_grid_get_child_at(GTK_GRID(box), index, 0);
7524
7525 if(boxcount > 0)
7526 {
7527 /* Decrease the count by 1 */
7528 boxcount--;
7529 g_object_set_data(G_OBJECT(box), "_dw_boxcount", GINT_TO_POINTER(boxcount));
7530 }
7531 /* If we haven't incremented the reference count... raise it before removal */
7532 if(item && g_object_get_data(G_OBJECT(item), "_dw_padding"))
7533 gtk_widget_destroy(item);
7534 else if(item)
7535 {
7536 if(!g_object_get_data(G_OBJECT(item), "_dw_refed"))
7537 {
7538 g_object_ref(G_OBJECT(item));
7539 g_object_set_data(G_OBJECT(item), "_dw_refed", GINT_TO_POINTER(1));
7540 }
7541 /* Remove the widget from the box */
7542 gtk_container_remove(GTK_CONTAINER(box), item);
7543 if(boxtype == DW_VERT)
7544 gtk_grid_remove_row(GTK_GRID(box), index);
7545 else
7546 gtk_grid_remove_column(GTK_GRID(box), index);
7547 retval = item;
7548 }
7549 }
7550 return retval;
7551 }
7552
7553 /*
7554 * Pack windows (widgets) into a box at an arbitrary location.
7555 * Parameters:
7556 * box: Window handle of the box to be packed into.
7557 * item: Window handle of the item to pack.
7558 * index: 0 based index of packed items.
7559 * width: Width in pixels of the item or -1 to be self determined.
7560 * height: Height in pixels of the item or -1 to be self determined.
7561 * hsize: TRUE if the window (widget) should expand horizontally to fill space given.
7562 * vsize: TRUE if the window (widget) should expand vertically to fill space given.
7563 * pad: Number of pixels of padding around the item.
7564 */
7565 void API dw_box_pack_at_index(HWND box, HWND item, int index, int width, int height, int hsize, int vsize, int pad)
7566 {
7567 _dw_box_pack(box, item, index, width, height, hsize, vsize, pad, "dw_box_pack_at_index()");
7568 }
7569
7570 /*
7571 * Pack windows (widgets) into a box from the start (or top).
7572 * Parameters:
7573 * box: Window handle of the box to be packed into.
7574 * item: Window handle of the item to pack.
7575 * width: Width in pixels of the item or -1 to be self determined.
7576 * height: Height in pixels of the item or -1 to be self determined.
7577 * hsize: TRUE if the window (widget) should expand horizontally to fill space given.
7578 * vsize: TRUE if the window (widget) should expand vertically to fill space given.
7579 * pad: Number of pixels of padding around the item.
7580 */
7581 void API dw_box_pack_start(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad)
7582 {
7583 /* 65536 is the table limit on GTK...
7584 * seems like a high enough value we will never hit it here either.
7585 */
7586 _dw_box_pack(box, item, 65536, width, height, hsize, vsize, pad, "dw_box_pack_start()");
7587 }
7588
7589 /*
7590 * Pack windows (widgets) into a box from the end (or bottom).
7591 * Parameters:
7592 * box: Window handle of the box to be packed into.
7593 * item: Window handle of the item to pack.
7594 * width: Width in pixels of the item or -1 to be self determined.
7595 * height: Height in pixels of the item or -1 to be self determined.
7596 * hsize: TRUE if the window (widget) should expand horizontally to fill space given.
7597 * vsize: TRUE if the window (widget) should expand vertically to fill space given.
7598 * pad: Number of pixels of padding around the item.
7599 */
7600 void API dw_box_pack_end(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad)
7601 {
7602 _dw_box_pack(box, item, 0, width, height, hsize, vsize, pad, "dw_box_pack_end()");
7603 }
7604
7605
7606 union extents_union { guchar **gu_extents; unsigned long **extents; };
7607 static GdkAtom extents_atom = 0;
7608 static time_t extents_time = 0;
7609
7610 static gboolean _dw_property_notify(GtkWidget *window, GdkEventProperty* event, GdkWindow *gdkwindow)
7611 {
7612 /* Check to see if we got a property change */
7613 if(event->state == GDK_PROPERTY_NEW_VALUE && event->atom == extents_atom && event->window == gdkwindow)
7614 extents_time = 0;
7615 return FALSE;
7616 }
7617
7618 /* Internal function to figure out the frame extents of an unmapped window */
7619 void _dw_get_frame_extents(GtkWidget *window, int *vert, int *horz)
7620 {
7621 if(gtk_window_get_decorated(GTK_WINDOW(window)))
7622 {
7623 const char *request = "_NET_REQUEST_FRAME_EXTENTS";
7624 unsigned long *extents = NULL;
7625 union extents_union eu;
7626 GdkAtom request_extents = gdk_atom_intern(request, FALSE);
7627 GdkWindow *gdkwindow = gtk_widget_get_window(window);
7628 GdkDisplay *display = gtk_widget_get_display(window);
7629
7630 if(!extents_atom)
7631 extents_atom = gdk_atom_intern("_NET_FRAME_EXTENTS", FALSE);
7632
7633 /* Set some rational defaults.. just in case */
7634 *vert = 28;
7635 *horz = 12;
7636
7637 /* See if the current window manager supports _NET_REQUEST_FRAME_EXTENTS */
7638 if(gdk_x11_screen_supports_net_wm_hint(gdk_screen_get_default(), request_extents))
7639 {
7640 Display *xdisplay = GDK_DISPLAY_XDISPLAY(display);
7641 GdkWindow *root_window = gdk_get_default_root_window();
7642 Window xroot_window = GDK_WINDOW_XID(root_window);
7643 Atom extents_request_atom = gdk_x11_get_xatom_by_name_for_display(display, request);
7644 unsigned long window_id = GDK_WINDOW_XID(gdkwindow);
7645 XEvent xevent = {0};
7646 time_t currtime;
7647 gulong connid;
7648
7649 xevent.xclient.type = ClientMessage;
7650 xevent.xclient.message_type = extents_request_atom;
7651 xevent.xclient.display = xdisplay;
7652 xevent.xclient.window = window_id;
7653 xevent.xclient.format = 32;
7654
7655 /* Send the property request */
7656 XSendEvent(xdisplay, xroot_window, False,
7657 (SubstructureRedirectMask | SubstructureNotifyMask),
7658 &xevent);
7659
7660 /* Connect a signal to look for the property change */
7661 connid = g_signal_connect(G_OBJECT(window), "property_notify_event", G_CALLBACK(_dw_property_notify), gdkwindow);
7662
7663 /* Record the request time */
7664 time(&extents_time);
7665
7666 /* Look for the property notify event */
7667 do
7668 {
7669 dw_main_iteration();
7670 time(&currtime);
7671 }
7672 while(currtime - extents_time < 2);
7673
7674 /* Remove the signal handler now that we are done */
7675 g_signal_handler_disconnect(G_OBJECT(window), connid);
7676 }
7677
7678 /* Attempt to retrieve window's frame extents. */
7679 eu.extents = &extents;
7680 if(gdk_property_get(gdkwindow,
7681 extents_atom,
7682 gdk_atom_intern("CARDINAL", FALSE),
7683 0, sizeof(unsigned long)*4, FALSE,
7684 NULL, NULL, NULL, eu.gu_extents))
7685 {
7686 *horz = extents[0] + extents[1];
7687 *vert = extents[2] + extents[3];
7688 }
7689 }
7690 else
7691 *horz = *vert = 0;
7692 }
7693
7694 /*
7695 * Sets the size of a given window (widget).
7696 * Parameters:
7697 * handle: Window (widget) handle.
7698 * width: New width in pixels.
7699 * height: New height in pixels.
7700 */
7701 void dw_window_set_size(HWND handle, unsigned long width, unsigned long height)
7702 {
7703 if(!handle)
7704 return;
7705
7706 if(GTK_IS_WINDOW(handle))
7707 {
7708 GdkWindow *window = gtk_widget_get_window(handle);
7709 int cx = 0, cy = 0;
7710
7711 /* Window is mapped query the frame size directly */
7712 if(window && gtk_widget_get_mapped(handle))
7713 {
7714 GdkRectangle frame;
7715 gint gwidth, gheight;
7716
7717 /* Calculate the border size */
7718 gdk_window_get_frame_extents(window, &frame);
7719 gdk_window_get_geometry(window, NULL, NULL, &gwidth, &gheight);
7720
7721 cx = frame.width - gwidth;
7722 if(cx < 0)
7723 cx = 0;
7724 cy = frame.height - gheight;
7725 if(cy < 0)
7726 cy = 0;
7727 }
7728 else
7729 {
7730 /* Check if we have cached frame size values */
7731 if(!((cx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_frame_width"))) |
7732 (cy = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_frame_height")))))
7733 {
7734 /* If not try to ask the window manager for the estimated size...
7735 * and finally if all else fails, guess.
7736 */
7737 _dw_get_frame_extents(handle, &cy, &cx);
7738 /* Cache values for later use */
7739 g_object_set_data(G_OBJECT(handle), "_dw_frame_width", GINT_TO_POINTER(cx));
7740 g_object_set_data(G_OBJECT(handle), "_dw_frame_height", GINT_TO_POINTER(cy));
7741 }
7742 /* Save the size for when it is shown */
7743 g_object_set_data(G_OBJECT(handle), "_dw_width", GINT_TO_POINTER(width));
7744 g_object_set_data(G_OBJECT(handle), "_dw_height", GINT_TO_POINTER(height));
7745 }
7746 /* Resize minus the border size */
7747 if(width > cx && height > cy)
7748 {
7749 gtk_window_resize(GTK_WINDOW(handle), width - cx , height - cy );
7750 gtk_window_set_default_size(GTK_WINDOW(handle), width - cx, height - cy);
7751 }
7752 }
7753 else
7754 gtk_widget_set_size_request(handle, width, height);
7755 }
7756
7757 /*
7758 * Gets the size the system thinks the widget should be.
7759 * Parameters:
7760 * handle: Window handle of the item to be back.
7761 * width: Width in pixels of the item or NULL if not needed.
7762 * height: Height in pixels of the item or NULL if not needed.
7763 */
7764 void API dw_window_get_preferred_size(HWND handle, int *width, int *height)
7765 {
7766 if(GTK_IS_SCROLLED_WINDOW(handle))
7767 {
7768 gint scrolledwidth, scrolledheight;
7769
7770 _get_scrolled_size(handle, &scrolledwidth, &scrolledheight);
7771
7772 if(width)
7773 *width = scrolledwidth;
7774 if(height)
7775 *height = scrolledheight;
7776 }
7777 else
7778 {
7779 if(width)
7780 gtk_widget_get_preferred_width(handle, NULL, width);
7781 if(height)
7782 gtk_widget_get_preferred_height(handle, NULL, height);
7783 }
7784 }
7785
7786 /* Internal version to simplify the code with multiple versions of GTK */
7787 int _dw_screen_width(void)
7788 {
7789 GdkDisplay *display = gdk_display_get_default();
7790
7791 if(display)
7792 {
7793 GdkMonitor *monitor = gdk_display_get_primary_monitor(display);
7794
7795 if(monitor)
7796 {
7797 GdkRectangle rc = { 0, 0, 0 ,0 };
7798 gdk_monitor_get_geometry(monitor, &rc);
7799 return rc.width;
7800 }
7801 }
7802 return 0;
7803 }
7804
7805 /*
7806 * Returns the width of the screen.
7807 */
7808 int dw_screen_width(void)
7809 {
7810 return _dw_screen_width();
7811 }
7812
7813 /* Internal version to simplify the code with multiple versions of GTK */
7814 int _dw_screen_height(void)
7815 {
7816 GdkDisplay *display = gdk_display_get_default();
7817
7818 if(display)
7819 {
7820 GdkMonitor *monitor = gdk_display_get_primary_monitor(display);
7821
7822 if(monitor)
7823 {
7824 GdkRectangle rc = { 0, 0, 0 ,0 };
7825 gdk_monitor_get_geometry(monitor, &rc);
7826 return rc.height;
7827 }
7828 }
7829 return 0;
7830 }
7831
7832 /*
7833 * Returns the height of the screen.
7834 */
7835 int dw_screen_height(void)
7836 {
7837 return _dw_screen_height();
7838 }
7839
7840 /* This should return the current color depth */
7841 unsigned long dw_color_depth_get(void)
7842 {
7843 GdkVisual *vis = gdk_screen_get_system_visual(gdk_screen_get_default());
7844 return gdk_visual_get_depth(vis);
7845 }
7846
7847 /*
7848 * Sets the gravity of a given window (widget).
7849 * Gravity controls which corner of the screen and window the position is relative to.
7850 * Parameters:
7851 * handle: Window (widget) handle.
7852 * horz: DW_GRAV_LEFT (default), DW_GRAV_RIGHT or DW_GRAV_CENTER.
7853 * vert: DW_GRAV_TOP (default), DW_GRAV_BOTTOM or DW_GRAV_CENTER.
7854 */
7855 void API dw_window_set_gravity(HWND handle, int horz, int vert)
7856 {
7857 dw_window_set_data(handle, "_dw_grav_horz", DW_INT_TO_POINTER(horz));
7858 dw_window_set_data(handle, "_dw_grav_vert", DW_INT_TO_POINTER(vert));
7859 }
7860
7861 /*
7862 * Sets the position of a given window (widget).
7863 * Parameters:
7864 * handle: Window (widget) handle.
7865 * x: X location from the bottom left.
7866 * y: Y location from the bottom left.
7867 */
7868 void dw_window_set_pos(HWND handle, long x, long y)
7869 {
7870 if(!handle)
7871 return;
7872
7873 {
7874 GdkWindow *window = NULL;
7875
7876 if(GTK_IS_WINDOW(handle))
7877 {
7878 GdkWindow *window = gtk_widget_get_window(handle);
7879 int horz = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_grav_horz"));
7880 int vert = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_grav_vert"));
7881 int cx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_frame_width"));
7882 int cy = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_frame_height"));
7883 int newx = x, newy = y, width = 0, height = 0;
7884
7885 /* If the window is mapped */
7886 if(window && gtk_widget_get_mapped(handle))
7887 {
7888 /* If we need the width or height... */
7889 if(horz || vert)
7890 {
7891 GdkRectangle frame;
7892 int count = 0;
7893
7894 /* Get the frame size */
7895 gdk_window_get_frame_extents(window, &frame);
7896
7897 /* FIXME: Sometimes we get returned an invalid 200x200
7898 * result... so if we get this... try the call a second
7899 * time and hope for a better result.
7900 */
7901 while((frame.width == 200 || frame.width == (200 + cx)) &&
7902 (frame.height == 200 || frame.height == (200 + cy)) && count < 10)
7903 {
7904 _dw_msleep(1);
7905 count++;
7906 gdk_window_get_frame_extents(window, &frame);
7907 }
7908 width = frame.width;
7909 height = frame.height;
7910 }
7911 }
7912 else
7913 {
7914 /* Check if we have cached frame size values */
7915 if(!(cx | cy))
7916 {
7917 /* If not try to ask the window manager for the estimated size...
7918 * and finally if all else fails, guess.
7919 */
7920 _dw_get_frame_extents(handle, &cy, &cx);
7921 /* Cache values for later use */
7922 g_object_set_data(G_OBJECT(handle), "_dw_frame_width", GINT_TO_POINTER(cx));
7923 g_object_set_data(G_OBJECT(handle), "_dw_frame_height", GINT_TO_POINTER(cy));
7924 }
7925 /* Save the positions for when it is shown */
7926 g_object_set_data(G_OBJECT(handle), "_dw_x", GINT_TO_POINTER(x));
7927 g_object_set_data(G_OBJECT(handle), "_dw_y", GINT_TO_POINTER(y));
7928 g_object_set_data(G_OBJECT(handle), "_dw_pos", GINT_TO_POINTER(1));
7929 /* Check to see if there is a pending size request too */
7930 width = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_width"));
7931 height = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), "_dw_height"));
7932 if(!width || !height)
7933 {
7934 /* Ask what GTK is planning on suggesting for the window size */
7935 gtk_window_get_size(GTK_WINDOW(handle), !width ? &width : NULL, !height ? &height : NULL);
7936 }
7937 /* Add the frame size to it */
7938 width += cx;
7939 height += cy;
7940 }
7941 /* Do any gravity calculations */
7942 if(horz || vert)
7943 {
7944 /* Handle horizontal center gravity */
7945 if((horz & 0xf) == DW_GRAV_CENTER)
7946 newx += ((_dw_screen_width() / 2) - (width / 2));
7947 /* Handle right gravity */
7948 else if((horz & 0xf) == DW_GRAV_RIGHT)
7949 newx = _dw_screen_width() - width - x;
7950 /* Handle vertical center gravity */
7951 if((vert & 0xf) == DW_GRAV_CENTER)
7952 newy += ((_dw_screen_height() / 2) - (height / 2));
7953 else if((vert & 0xf) == DW_GRAV_BOTTOM)
7954 newy = _dw_screen_height() - height - y;
7955
7956 /* Adjust the values to avoid Gnome bar if requested */
7957 if((horz | vert) & DW_GRAV_OBSTACLES)
7958 {
7959 GdkRectangle rect = { 0, 0, 0, 0 };
7960 GdkDisplay *display = gdk_display_get_default();
7961
7962 if(display)
7963 {
7964 GdkMonitor *monitor = gdk_display_get_primary_monitor(display);
7965
7966 if(monitor)
7967 gdk_monitor_get_workarea(monitor, &rect);
7968 }
7969 if(horz & DW_GRAV_OBSTACLES)
7970 {
7971 if((horz & 0xf) == DW_GRAV_LEFT)
7972 newx += rect.x;
7973 else if((horz & 0xf) == DW_GRAV_RIGHT)
7974 newx -= _dw_screen_width() - (rect.x + rect.width);
7975 }
7976 if(vert & DW_GRAV_OBSTACLES)
7977 {
7978 if((vert & 0xf) == DW_GRAV_TOP)
7979 newy += rect.y;
7980 else if((vert & 0xf) == DW_GRAV_BOTTOM)
7981 newy -= _dw_screen_height() - (rect.y + rect.height);
7982 }
7983 }
7984 }
7985 /* Finally move the window into place */
7986 gtk_window_move(GTK_WINDOW(handle), newx, newy);
7987 }
7988 else if((window = gtk_widget_get_window(handle)))
7989 gdk_window_move(window, x, y);
7990 }
7991 }
7992
7993 /*
7994 * Sets the position and size of a given window (widget).
7995 * Parameters:
7996 * handle: Window (widget) handle.
7997 * x: X location from the bottom left.
7998 * y: Y location from the bottom left.
7999 * width: Width of the widget.
8000 * height: Height of the widget.
8001 */
8002 void dw_window_set_pos_size(HWND handle, long x, long y, unsigned long width, unsigned long height)
8003 {
8004 dw_window_set_size(handle, width, height);
8005 dw_window_set_pos(handle, x, y);
8006 }
8007
8008 /*
8009 * Gets the position and size of a given window (widget).
8010 * Parameters:
8011 * handle: Window (widget) handle.
8012 * x: X location from the bottom left.
8013 * y: Y location from the bottom left.
8014 * width: Width of the widget.
8015 * height: Height of the widget.
8016 */
8017 void dw_window_get_pos_size(HWND handle, long *x, long *y, ULONG *width, ULONG *height)
8018 {
8019 gint gx = 0, gy = 0, gwidth = 0, gheight = 0;
8020
8021 {
8022 GdkWindow *window;
8023
8024 /* Can only query if the window is realized */
8025 if(handle && (window = gtk_widget_get_window(handle)))
8026 {
8027 /* If it is a toplevel window */
8028 if(GTK_IS_WINDOW(handle))
8029 {
8030 if(gtk_widget_get_mapped(handle))
8031 {
8032 GdkRectangle frame;
8033
8034 /* Calculate the border rectangle */
8035 gdk_window_get_frame_extents(window, &frame);
8036 gx = frame.x;
8037 gy = frame.y;
8038 gwidth = frame.width;
8039 gheight = frame.height;
8040 }
8041 }
8042 else
8043 {
8044 /* Get an individual widget coordinates */
8045 gdk_window_get_geometry(window, &gx, &gy, &gwidth, &gheight);
8046 gdk_window_get_root_origin(window, &gx, &gy);
8047 }
8048 }
8049 }
8050 /* Fill in the requested fields */
8051 if(x)
8052 *x = gx;
8053 if(y)
8054 *y = gy;
8055 if(width)
8056 *width = gwidth;
8057 if(height)
8058 *height = gheight;
8059 }
8060
8061 /*
8062 * Sets the style of a given window (widget).
8063 * Parameters:
8064 * handle: Window (widget) handle.
8065 * width: New width in pixels.
8066 * height: New height in pixels.
8067 */
8068 void dw_window_set_style(HWND handle, unsigned long style, unsigned long mask)
8069 {
8070 GtkWidget *handle2 = handle;
8071
8072 if(GTK_IS_SCROLLED_WINDOW(handle))
8073 {
8074 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8075 if(tmp)
8076 handle2 = tmp;
8077 }
8078 else if(GTK_IS_FRAME(handle))
8079 {
8080 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_label");
8081 if(tmp && GTK_IS_LABEL(tmp))
8082 handle2 = tmp;
8083 }
8084 else if(GTK_IS_BUTTON(handle))
8085 {
8086 if(mask & DW_BS_NOBORDER)
8087 {
8088 if(style & DW_BS_NOBORDER)
8089 {
8090 gtk_button_set_relief((GtkButton *)handle, GTK_RELIEF_NONE);
8091 }
8092 else
8093 {
8094 gtk_button_set_relief((GtkButton *)handle, GTK_RELIEF_NORMAL);
8095 }
8096 }
8097 }
8098 if ( GTK_IS_LABEL(handle2) )
8099 {
8100 gfloat x=DW_LEFT, y=DW_CENTER;
8101 /* horizontal... */
8102 if ( style & DW_DT_CENTER )
8103 x = DW_CENTER;
8104 if ( style & DW_DT_RIGHT )
8105 x = DW_RIGHT;
8106 if ( style & DW_DT_LEFT )
8107 x = DW_LEFT;
8108 /* vertical... */
8109 if ( style & DW_DT_VCENTER )
8110 y = DW_CENTER;
8111 if ( style & DW_DT_TOP )
8112 y = DW_TOP;
8113 if ( style & DW_DT_BOTTOM )
8114 y = DW_BOTTOM;
8115 gtk_label_set_xalign(GTK_LABEL(handle2), x);
8116 gtk_label_set_yalign(GTK_LABEL(handle2), y);
8117 if ( style & DW_DT_WORDBREAK )
8118 gtk_label_set_line_wrap( GTK_LABEL(handle), TRUE );
8119 }
8120 if ( GTK_IS_CHECK_MENU_ITEM(handle2) && (mask & (DW_MIS_CHECKED | DW_MIS_UNCHECKED)) )
8121 {
8122 int check = 0;
8123
8124 if ( style & DW_MIS_CHECKED )
8125 check = 1;
8126
8127 _dw_ignore_click = 1;
8128 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(handle2)) != check)
8129 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(handle2), check);
8130 _dw_ignore_click = 0;
8131 }
8132 if ( (GTK_IS_CHECK_MENU_ITEM(handle2) || GTK_IS_MENU_ITEM(handle2)) && (mask & (DW_MIS_ENABLED | DW_MIS_DISABLED) ))
8133 {
8134 _dw_ignore_click = 1;
8135 if ( style & DW_MIS_ENABLED )
8136 gtk_widget_set_sensitive( handle2, TRUE );
8137 else
8138 gtk_widget_set_sensitive( handle2, FALSE );
8139 _dw_ignore_click = 0;
8140 }
8141 }
8142
8143 /*
8144 * Adds a new page to specified notebook.
8145 * Parameters:
8146 * handle: Window (widget) handle.
8147 * flags: Any additional page creation flags.
8148 * front: If TRUE page is added at the beginning.
8149 */
8150 unsigned long dw_notebook_page_new(HWND handle, unsigned long flags, int front)
8151 {
8152 int z;
8153 GtkWidget **pagearray;
8154
8155 pagearray = (GtkWidget **)g_object_get_data(G_OBJECT(handle), "_dw_pagearray");
8156
8157 if(pagearray)
8158 {
8159 for(z=0;z<256;z++)
8160 {
8161 if(!pagearray[z])
8162 {
8163 char text[101] = {0};
8164 int num = z;
8165
8166 if(front)
8167 num |= 1 << 16;
8168
8169 snprintf(text, 100, "_dw_page%d", z);
8170 /* Save the real id and the creation flags */
8171 g_object_set_data(G_OBJECT(handle), text, GINT_TO_POINTER(num));
8172 return z;
8173 }
8174 }
8175 }
8176
8177 /* Hopefully this won't happen. */
8178 return 256;
8179 }
8180
8181 /* Return the physical page id from the logical page id */
8182 int _get_physical_page(HWND handle, unsigned long pageid)
8183 {
8184 int z;
8185 GtkWidget *thispage, **pagearray = g_object_get_data(G_OBJECT(handle), "_dw_pagearray");
8186
8187 if(pagearray)
8188 {
8189 for(z=0;z<256;z++)
8190 {
8191 if((thispage = gtk_notebook_get_nth_page(GTK_NOTEBOOK(handle), z)))
8192 {
8193 if(thispage == pagearray[pageid])
8194 return z;
8195 }
8196 }
8197 }
8198 return 256;
8199 }
8200
8201 /*
8202 * Remove a page from a notebook.
8203 * Parameters:
8204 * handle: Handle to the notebook widget.
8205 * pageid: ID of the page to be destroyed.
8206 */
8207 void dw_notebook_page_destroy(HWND handle, unsigned int pageid)
8208 {
8209 int realpage;
8210 GtkWidget **pagearray;
8211
8212 realpage = _get_physical_page(handle, pageid);
8213 if(realpage > -1 && realpage < 256)
8214 {
8215 gtk_notebook_remove_page(GTK_NOTEBOOK(handle), realpage);
8216 if((pagearray = g_object_get_data(G_OBJECT(handle), "_dw_pagearray")))
8217 pagearray[pageid] = NULL;
8218 }
8219 }
8220
8221 /*
8222 * Queries the currently visible page ID.
8223 * Parameters:
8224 * handle: Handle to the notebook widget.
8225 */
8226 unsigned long dw_notebook_page_get(HWND handle)
8227 {
8228 int retval, phys;
8229
8230 phys = gtk_notebook_get_current_page(GTK_NOTEBOOK(handle));
8231 retval = _get_logical_page(handle, phys);
8232 return retval;
8233 }
8234
8235 /*
8236 * Sets the currently visibale page ID.
8237 * Parameters:
8238 * handle: Handle to the notebook widget.
8239 * pageid: ID of the page to be made visible.
8240 */
8241 void dw_notebook_page_set(HWND handle, unsigned int pageid)
8242 {
8243 int realpage;
8244
8245 realpage = _get_physical_page(handle, pageid);
8246 if(realpage > -1 && realpage < 256)
8247 gtk_notebook_set_current_page(GTK_NOTEBOOK(handle), pageid);
8248 }
8249
8250
8251 /*
8252 * Sets the text on the specified notebook tab.
8253 * Parameters:
8254 * handle: Notebook handle.
8255 * pageid: Page ID of the tab to set.
8256 * text: Pointer to the text to set.
8257 */
8258 void dw_notebook_page_set_text(HWND handle, unsigned long pageid, const char *text)
8259 {
8260 GtkWidget *child;
8261 int realpage;
8262
8263 realpage = _get_physical_page(handle, pageid);
8264 if(realpage < 0 || realpage > 255)
8265 {
8266 char ptext[101] = {0};
8267 int num;
8268
8269 snprintf(ptext, 100, "_dw_page%d", (int)pageid);
8270 num = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), ptext));
8271 realpage = 0xFF & num;
8272 }
8273
8274 if(realpage > -1 && realpage < 256)
8275 {
8276 child = gtk_notebook_get_nth_page(GTK_NOTEBOOK(handle), realpage);
8277 if(child)
8278 gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(handle), child, text);
8279 }
8280 }
8281
8282 /*
8283 * Sets the text on the specified notebook tab status area.
8284 * Parameters:
8285 * handle: Notebook handle.
8286 * pageid: Page ID of the tab to set.
8287 * text: Pointer to the text to set.
8288 */
8289 void dw_notebook_page_set_status_text(HWND handle, unsigned long pageid, const char *text)
8290 {
8291 /* TODO (if possible) */
8292 }
8293
8294 /*
8295 * Packs the specified box into the notebook page.
8296 * Parameters:
8297 * handle: Handle to the notebook to be packed.
8298 * pageid: Page ID in the notebook which is being packed.
8299 * page: Box handle to be packed.
8300 */
8301 void dw_notebook_pack(HWND handle, unsigned long pageid, HWND page)
8302 {
8303 GtkWidget *label, *child, *oldlabel, **pagearray;
8304 const gchar *text = NULL;
8305 int num, z, realpage = -1, pad;
8306 char ptext[101] = {0};
8307
8308 snprintf(ptext, 100, "_dw_page%d", (int)pageid);
8309 num = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(handle), ptext));
8310 g_object_set_data(G_OBJECT(handle), ptext, NULL);
8311 pagearray = (GtkWidget **)g_object_get_data(G_OBJECT(handle), "_dw_pagearray");
8312
8313 if(!pagearray)
8314 return;
8315
8316 /* The page already exists... so get it's current page */
8317 if(pagearray[pageid])
8318 {
8319 for(z=0;z<256;z++)
8320 {
8321 child = gtk_notebook_get_nth_page(GTK_NOTEBOOK(handle), z);
8322 if(child == pagearray[pageid])
8323 {
8324 oldlabel = gtk_notebook_get_tab_label(GTK_NOTEBOOK(handle), child);
8325 if(oldlabel)
8326 text = gtk_label_get_text(GTK_LABEL(oldlabel));
8327 gtk_notebook_remove_page(GTK_NOTEBOOK(handle), z);
8328 realpage = z;
8329 break;
8330 }
8331 }
8332 }
8333
8334 pagearray[pageid] = page;
8335
8336 label = gtk_label_new(text ? text : "");
8337
8338 if(GTK_IS_GRID(page))
8339 {
8340 pad = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(page), "_dw_boxpad"));
8341 gtk_container_set_border_width(GTK_CONTAINER(page), pad);
8342 }
8343
8344 if(realpage != -1)
8345 gtk_notebook_insert_page(GTK_NOTEBOOK(handle), page, label, realpage);
8346 else if(num & ~(0xFF))
8347 gtk_notebook_insert_page(GTK_NOTEBOOK(handle), page, label, 0);
8348 else
8349 gtk_notebook_insert_page(GTK_NOTEBOOK(handle), page, label, 256);
8350 }
8351
8352 /*
8353 * Appends the specified text to the listbox's (or combobox) entry list.
8354 * Parameters:
8355 * handle: Handle to the listbox to be appended to.
8356 * text: Text to append into listbox.
8357 */
8358 void dw_listbox_append(HWND handle, const char *text)
8359 {
8360 dw_listbox_insert(handle, text, -1);
8361 }
8362
8363 /*
8364 * Inserts the specified text int the listbox's (or combobox) entry list at the
8365 * position indicated.
8366 * Parameters:
8367 * handle: Handle to the listbox to be appended to.
8368 * text: Text to insert into listbox.
8369 * pos: 0-based index into listbox. -1 will append
8370 */
8371 void dw_listbox_insert(HWND handle, const char *text, int pos)
8372 {
8373 GtkWidget *handle2 = handle;
8374 GtkListStore *store = NULL;
8375
8376 /* Get the inner handle for scrolled controls */
8377 if(GTK_IS_SCROLLED_WINDOW(handle))
8378 {
8379 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8380 if(tmp)
8381 handle2 = tmp;
8382 }
8383 if(handle2)
8384 {
8385 GtkTreeIter iter;
8386
8387 /* Make sure it is the correct tree type */
8388 if(GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8389 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8390 else if(GTK_IS_COMBO_BOX(handle2))
8391 store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(handle2));
8392
8393 if(!store)
8394 return;
8395
8396 if(pos < 0)
8397 {
8398 /* Insert an entry at the end */
8399 gtk_list_store_append(store, &iter);
8400 }
8401 else
8402 {
8403 /* Insert at position */
8404 gtk_list_store_insert(store, &iter, pos);
8405 }
8406 gtk_list_store_set (store, &iter, 0, text, -1);
8407 }
8408 }
8409
8410 /*
8411 * Appends the specified text items to the listbox's (or combobox) entry list.
8412 * Parameters:
8413 * handle: Handle to the listbox to be appended to.
8414 * text: Text strings to append into listbox.
8415 * count: Number of text strings to append
8416 */
8417 void dw_listbox_list_append(HWND handle, char **text, int count)
8418 {
8419 GtkWidget *handle2 = handle;
8420 GtkListStore *store = NULL;
8421
8422 /* Get the inner handle for scrolled controls */
8423 if(GTK_IS_SCROLLED_WINDOW(handle))
8424 {
8425 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8426 if(tmp)
8427 handle2 = tmp;
8428 }
8429 if(handle2)
8430 {
8431 int z;
8432 GtkTreeIter iter;
8433
8434 /* Make sure it is the correct tree type */
8435 if(GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8436 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8437 else if(GTK_IS_COMBO_BOX(handle2))
8438 store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(handle2));
8439
8440 if(!store)
8441 return;
8442
8443 /* Insert entries at the end */
8444 for(z=0;z<count;z++)
8445 {
8446 gtk_list_store_append(store, &iter);
8447 gtk_list_store_set (store, &iter, 0, text[z], -1);
8448 }
8449 }
8450 }
8451
8452 /*
8453 * Clears the listbox's (or combobox) list of all entries.
8454 * Parameters:
8455 * handle: Handle to the listbox to be cleared.
8456 */
8457 void dw_listbox_clear(HWND handle)
8458 {
8459 GtkWidget *handle2 = handle;
8460 GtkListStore *store = NULL;
8461
8462 /* Get the inner handle for scrolled controls */
8463 if(GTK_IS_SCROLLED_WINDOW(handle))
8464 {
8465 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8466 if(tmp)
8467 handle2 = tmp;
8468 }
8469 if(handle2)
8470 {
8471 /* Make sure it is the correct tree type */
8472 if(GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8473 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8474 else if(GTK_IS_COMBO_BOX(handle2))
8475 store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(handle2));
8476
8477 if(!store)
8478 return;
8479 /* Clear the list */
8480 gtk_list_store_clear(store);
8481 }
8482 }
8483
8484 /*
8485 * Returns the listbox's item count.
8486 * Parameters:
8487 * handle: Handle to the listbox to be counted
8488 */
8489 int dw_listbox_count(HWND handle)
8490 {
8491 GtkWidget *handle2 = handle;
8492 GtkListStore *store = NULL;
8493 int retval = 0;
8494
8495 /* Get the inner handle for scrolled controls */
8496 if(GTK_IS_SCROLLED_WINDOW(handle))
8497 {
8498 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8499 if(tmp)
8500 handle2 = tmp;
8501 }
8502 if(handle2)
8503 {
8504 /* Make sure it is the correct tree type */
8505 if(GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8506 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8507 else if(GTK_IS_COMBO_BOX(handle2))
8508 store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(handle2));
8509
8510 if(store)
8511 {
8512 /* Get the number of children at the top level */
8513 retval = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
8514 }
8515 }
8516 return retval;
8517 }
8518
8519 /*
8520 * Sets the topmost item in the viewport.
8521 * Parameters:
8522 * handle: Handle to the listbox to be cleared.
8523 * top: Index to the top item.
8524 */
8525 void dw_listbox_set_top(HWND handle, int top)
8526 {
8527 GtkWidget *handle2 = handle;
8528
8529 if(GTK_IS_SCROLLED_WINDOW(handle))
8530 {
8531 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8532 if(tmp)
8533 handle2 = tmp;
8534 }
8535 /* Make sure it is the correct tree type */
8536 if(handle2 && GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8537 {
8538 GtkAdjustment *adjust = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(handle));
8539 GtkListStore *store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8540
8541 if(store && adjust)
8542 {
8543 /* Get the number of children at the top level */
8544 gint rowcount = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
8545 gdouble pagesize = gtk_adjustment_get_page_size(adjust);
8546 gdouble upper = gtk_adjustment_get_upper(adjust) - pagesize;
8547 gdouble lower = gtk_adjustment_get_lower(adjust);
8548 gdouble change;
8549
8550 /* Safety check */
8551 if(rowcount < 2)
8552 return;
8553
8554 /* Verify the range */
8555 rowcount--;
8556 if(top > rowcount)
8557 top = rowcount;
8558
8559 change = ((gdouble)top/(gdouble)rowcount) * (upper - lower);
8560
8561 gtk_adjustment_set_value(adjust, change + lower);
8562 }
8563 }
8564 }
8565
8566 /*
8567 * Copies the given index item's text into buffer.
8568 * Parameters:
8569 * handle: Handle to the listbox to be queried.
8570 * index: Index into the list to be queried.
8571 * buffer: Buffer where text will be copied.
8572 * length: Length of the buffer (including NULL).
8573 */
8574 void dw_listbox_get_text(HWND handle, unsigned int index, char *buffer, unsigned int length)
8575 {
8576 GtkWidget *handle2 = handle;
8577 GtkListStore *store = NULL;
8578
8579 /* Get the inner handle for scrolled controls */
8580 if(GTK_IS_SCROLLED_WINDOW(handle))
8581 {
8582 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8583 if(tmp)
8584 handle2 = tmp;
8585 }
8586 if(handle2)
8587 {
8588 /* Make sure it is the correct tree type */
8589 if(GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8590 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8591 else if(GTK_IS_COMBO_BOX(handle2))
8592 store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(handle2));
8593
8594 if(store && index < gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL))
8595 {
8596 GtkTreeIter iter;
8597
8598 /* Get the nth child at the top level */
8599 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, index))
8600 {
8601 /* Get the text */
8602 gchar *text;
8603 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, _DW_DATA_TYPE_STRING, &text, -1);
8604 if(text)
8605 {
8606 strncpy(buffer, text, length);
8607 g_free(text);
8608 }
8609 return;
8610 }
8611 }
8612 }
8613 buffer[0] = '\0';
8614 }
8615
8616 /*
8617 * Sets the text of a given listbox entry.
8618 * Parameters:
8619 * handle: Handle to the listbox to be queried.
8620 * index: Index into the list to be queried.
8621 * buffer: Buffer where text will be copied.
8622 */
8623 void dw_listbox_set_text(HWND handle, unsigned int index, const char *buffer)
8624 {
8625 GtkWidget *handle2 = handle;
8626 GtkListStore *store = NULL;
8627
8628 /* Get the inner handle for scrolled controls */
8629 if(GTK_IS_SCROLLED_WINDOW(handle))
8630 {
8631 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8632 if(tmp)
8633 handle2 = tmp;
8634 }
8635 if(handle2)
8636 {
8637 /* Make sure it is the correct tree type */
8638 if(GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8639 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8640 else if(GTK_IS_COMBO_BOX(handle2))
8641 store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(handle2));
8642
8643 if(store && index < gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL))
8644 {
8645 GtkTreeIter iter;
8646
8647 /* Get the nth child at the top level */
8648 if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, index))
8649 {
8650 /* Update the text */
8651 gtk_list_store_set(store, &iter, buffer);
8652 }
8653 }
8654 }
8655 }
8656
8657 /*
8658 * Returns the index to the current selected item or -1 when done.
8659 * Parameters:
8660 * handle: Handle to the listbox to be queried.
8661 * where: Either the previous return or -1 to restart.
8662 */
8663 int dw_listbox_selected_multi(HWND handle, int where)
8664 {
8665 GtkWidget *handle2;
8666 GtkListStore *store = NULL;
8667 int retval = DW_LIT_NONE;
8668
8669 handle2 = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8670
8671 /* Make sure it is the correct tree type */
8672 if(handle2 && GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8673 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8674
8675 if(store)
8676 {
8677 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(handle2));
8678 GList *list = gtk_tree_selection_get_selected_rows(sel, NULL);
8679
8680 if(list)
8681 {
8682 int counter = 0;
8683 GtkTreePath *path = g_list_nth_data(list, 0);
8684
8685 while(path)
8686 {
8687 gint *indices = gtk_tree_path_get_indices(path);
8688
8689 if(indices && indices[0] > where)
8690 {
8691 retval = indices[0];
8692 break;
8693 }
8694
8695 counter++;
8696 path = g_list_nth_data(list, counter);
8697 }
8698
8699 g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
8700 g_list_free(list);
8701 }
8702 }
8703 return retval;
8704 }
8705
8706 /*
8707 * Returns the index to the item in the list currently selected.
8708 * Parameters:
8709 * handle: Handle to the listbox to be queried.
8710 */
8711 int dw_listbox_selected(HWND handle)
8712 {
8713 GtkWidget *handle2 = handle;
8714 GtkListStore *store = NULL;
8715 unsigned int retval = 0;
8716
8717 /* Get the inner handle for scrolled controls */
8718 if(GTK_IS_SCROLLED_WINDOW(handle))
8719 {
8720 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8721 if(tmp)
8722 handle2 = tmp;
8723 }
8724 if(handle2)
8725 {
8726 /* Make sure it is the correct tree type */
8727 if(GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8728 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8729 else if(GTK_IS_COMBO_BOX(handle2))
8730 store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(handle2));
8731
8732 if(store)
8733 {
8734 if(GTK_IS_TREE_VIEW(handle2))
8735 {
8736 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(handle2));
8737 GList *list = gtk_tree_selection_get_selected_rows(sel, NULL);
8738 if(list)
8739 {
8740 GtkTreePath *path = g_list_nth_data(list, 0);
8741 gint *indices = gtk_tree_path_get_indices(path);
8742
8743 if(indices)
8744 {
8745 retval = indices[0];
8746 }
8747
8748 g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
8749 g_list_free(list);
8750 }
8751 }
8752 else
8753 {
8754 GtkTreeIter iter;
8755 GtkTreePath *path;
8756
8757 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(handle2), &iter))
8758 {
8759 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
8760 if(path)
8761 {
8762 gint *indices = gtk_tree_path_get_indices(path);
8763
8764 if(indices)
8765 {
8766 retval = indices[0];
8767 }
8768 gtk_tree_path_free(path);
8769 }
8770 }
8771 }
8772 }
8773 }
8774 return retval;
8775 }
8776
8777 /*
8778 * Sets the selection state of a given index.
8779 * Parameters:
8780 * handle: Handle to the listbox to be set.
8781 * index: Item index.
8782 * state: TRUE if selected FALSE if unselected.
8783 */
8784 void dw_listbox_select(HWND handle, int index, int state)
8785 {
8786 GtkWidget *handle2 = handle;
8787 GtkListStore *store = NULL;
8788
8789 /* Get the inner handle for scrolled controls */
8790 if(GTK_IS_SCROLLED_WINDOW(handle))
8791 {
8792 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8793 if(tmp)
8794 handle2 = tmp;
8795 }
8796 if(handle2)
8797 {
8798 /* Make sure it is the correct tree type */
8799 if(GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8800 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8801 else if(GTK_IS_COMBO_BOX(handle2))
8802 store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(handle2));
8803
8804 if(store && index < gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL))
8805 {
8806 GtkTreeIter iter;
8807
8808 /* Get the nth child at the top level */
8809 if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, index))
8810 {
8811 if(GTK_IS_COMBO_BOX(handle2))
8812 {
8813 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(handle2), &iter);
8814 }
8815 else
8816 {
8817 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(handle2));
8818 if(state)
8819 {
8820 /* Select the item */
8821 gtk_tree_selection_select_iter(sel, &iter);
8822 }
8823 else
8824 {
8825 /* Deselect the item */
8826 gtk_tree_selection_unselect_iter(sel, &iter);
8827 }
8828 }
8829 }
8830 }
8831 }
8832 }
8833
8834 /*
8835 * Deletes the item with given index from the list.
8836 * Parameters:
8837 * handle: Handle to the listbox to be set.
8838 * index: Item index.
8839 */
8840 void dw_listbox_delete(HWND handle, int index)
8841 {
8842 GtkWidget *handle2 = handle;
8843 GtkListStore *store = NULL;
8844
8845 /* Get the inner handle for scrolled controls */
8846 if(GTK_IS_SCROLLED_WINDOW(handle))
8847 {
8848 GtkWidget *tmp = (GtkWidget *)g_object_get_data(G_OBJECT(handle), "_dw_user");
8849 if(tmp)
8850 handle2 = tmp;
8851 }
8852 if(handle2)
8853 {
8854 /* Make sure it is the correct tree type */
8855 if(GTK_IS_TREE_VIEW(handle2) && g_object_get_data(G_OBJECT(handle2), "_dw_tree_type") == GINT_TO_POINTER(_DW_TREE_TYPE_LISTBOX))
8856 store = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(handle2));
8857 else if(GTK_IS_COMBO_BOX(handle2))
8858 store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(handle2));
8859
8860 if(store)
8861 {
8862 GtkTreeIter iter;
8863
8864 /* Get the nth child at the top level */
8865 if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, index))
8866 {
8867 gtk_list_store_remove(store, &iter);
8868 }
8869 }
8870 }
8871 }
8872
8873 /* Function to do delayed positioning */
8874 gboolean _splitbar_set_percent(gpointer data)
8875 {
8876 GtkWidget *widget = data;
8877 float *percent = (float *)g_object_get_data(G_OBJECT(widget), "_dw_percent");
8878
8879 if(percent)
8880 {
8881 GtkAllocation alloc;
8882
8883 gtk_widget_get_allocation(widget, &alloc);
8884
8885 if(gtk_orientable_get_orientation(GTK_ORIENTABLE(widget)) == GTK_ORIENTATION_HORIZONTAL)
8886 gtk_paned_set_position(GTK_PANED(widget), (int)(alloc.width * (*percent / 100.0)));
8887 else
8888 gtk_paned_set_position(GTK_PANED(widget), (int)(alloc.height * (*percent / 100.0)));
8889 g_object_set_data(G_OBJECT(widget), "_dw_percent", NULL);
8890 free(percent);
8891 }
8892 return FALSE;
8893 }
8894
8895 /* Reposition the bar according to the percentage */
8896 static gint _splitbar_size_allocate(GtkWidget *widget, GtkAllocation *event, gpointer data)
8897 {
8898 float *percent = (float *)g_object_get_data(G_OBJECT(widget), "_dw_percent");
8899
8900 /* Prevent infinite recursion ;) */
8901 if(!percent || event->width < 20 || event->height < 20)
8902 return FALSE;
8903
8904 g_idle_add(_splitbar_set_percent, widget);
8905 return FALSE;
8906 }
8907
8908 /*
8909 * Creates a splitbar window (widget) with given parameters.
8910 * Parameters:
8911 * type: Value can be DW_VERT or DW_HORZ.
8912 * topleft: Handle to the window to be top or left.
8913 * bottomright: Handle to the window to be bottom or right.
8914 * Returns:
8915 * A handle to a splitbar window or NULL on failure.
8916 */
8917 HWND dw_splitbar_new(int type, HWND topleft, HWND bottomright, unsigned long id)
8918 {
8919 GtkWidget *tmp = NULL;
8920 float *percent = malloc(sizeof(float));
8921
8922 tmp = gtk_paned_new(type == DW_HORZ ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
8923 gtk_paned_pack1(GTK_PANED(tmp), topleft, TRUE, FALSE);
8924 gtk_paned_pack2(GTK_PANED(tmp), bottomright, TRUE, FALSE);
8925 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
8926 *percent = 50.0;
8927 g_object_set_data(G_OBJECT(tmp), "_dw_percent", (gpointer)percent);
8928 g_signal_connect(G_OBJECT(tmp), "size-allocate", G_CALLBACK(_splitbar_size_allocate), NULL);
8929 gtk_widget_show(tmp);
8930 return tmp;
8931 }
8932
8933 /*
8934 * Sets the position of a splitbar (pecentage).
8935 * Parameters:
8936 * handle: The handle to the splitbar returned by dw_splitbar_new().
8937 */
8938 void dw_splitbar_set(HWND handle, float percent)
8939 {
8940 float *mypercent = (float *)dw_window_get_data(handle, "_dw_percent");
8941 int size = 0, position;
8942
8943 if(gtk_orientable_get_orientation(GTK_ORIENTABLE(handle)) == GTK_ORIENTATION_HORIZONTAL)
8944 size = gtk_widget_get_allocated_width(handle);
8945 else
8946 size = gtk_widget_get_allocated_height(handle);
8947
8948 if(mypercent)
8949 *mypercent = percent;
8950
8951 if(size > 10)
8952 {
8953 position = (int)((float)size * (percent / 100.0));
8954
8955 gtk_paned_set_position(GTK_PANED(handle), position);
8956 }
8957 }
8958
8959 /*
8960 * Gets the position of a splitbar (pecentage).
8961 * Parameters:
8962 * handle: The handle to the splitbar returned by dw_splitbar_new().
8963 */
8964 float dw_splitbar_get(HWND handle)
8965 {
8966 float *percent = (float *)dw_window_get_data(handle, "_dw_percent");
8967
8968 if(percent)
8969 return *percent;
8970 return 0.0;
8971 }
8972
8973 /*
8974 * Creates a calendar window (widget) with given parameters.
8975 * Parameters:
8976 * id: Unique identifier for calendar widget
8977 * Returns:
8978 * A handle to a calendar window or NULL on failure.
8979 */
8980 HWND dw_calendar_new(unsigned long id)
8981 {
8982 GtkWidget *tmp;
8983 GtkCalendarDisplayOptions flags;
8984 time_t now;
8985 struct tm *tmdata;
8986
8987 tmp = gtk_calendar_new();
8988 gtk_widget_show(tmp);
8989 g_object_set_data(G_OBJECT(tmp), "_dw_id", GINT_TO_POINTER(id));
8990 /* select today */
8991 flags = GTK_CALENDAR_SHOW_HEADING|GTK_CALENDAR_SHOW_DAY_NAMES;
8992 gtk_calendar_set_display_options( GTK_CALENDAR(tmp), flags );
8993 now = time( NULL );
8994 tmdata = localtime( & now );
8995 gtk_calendar_select_month( GTK_CALENDAR(tmp), tmdata->tm_mon, 1900+tmdata->tm_year );
8996 gtk_calendar_select_day( GTK_CALENDAR(tmp), tmdata->tm_mday );
8997 return tmp;
8998 }
8999
9000 /*
9001 * Sets the current date of a calendar
9002 * Parameters:
9003 * handle: The handle to the calendar returned by dw_calendar_new().
9004 * year...
9005 */
9006 void dw_calendar_set_date(HWND handle, unsigned int year, unsigned int month, unsigned int day)
9007 {
9008 if(GTK_IS_CALENDAR(handle))
9009 {
9010 gtk_calendar_select_month(GTK_CALENDAR(handle),month-1,year);
9011 gtk_calendar_select_day(GTK_CALENDAR(handle), day);
9012 }
9013 }
9014
9015 /*
9016 * Gets the position of a splitbar (pecentage).
9017 * Parameters:
9018 * handle: The handle to the splitbar returned by dw_splitbar_new().
9019 */
9020 void dw_calendar_get_date(HWND handle, unsigned int *year, unsigned int *month, unsigned int *day)
9021 {
9022 if(GTK_IS_CALENDAR(handle))
9023 {
9024 gtk_calendar_get_date(GTK_CALENDAR(handle),year,month,day);
9025 *month = *month + 1;
9026 }
9027 }
9028
9029 /*
9030 * Sets the current focus item for a window/dialog.
9031 * Parameters:
9032 * handle: Handle to the dialog item to be focused.
9033 * Remarks:
9034 * This is for use after showing the window/dialog.
9035 */
9036 void API dw_window_set_focus(HWND handle)
9037 {
9038 if(!handle)
9039 return;
9040
9041 gtk_widget_grab_focus(handle);
9042 }
9043
9044 /*
9045 * Sets the default focus item for a window/dialog.
9046 * Parameters:
9047 * window: Toplevel window or dialog.
9048 * defaultitem: Handle to the dialog item to be default.
9049 * Remarks:
9050 * This is for use before showing the window/dialog.
9051 */
9052 void dw_window_default(HWND window, HWND defaultitem)
9053 {
9054 if(!window)
9055 return;
9056
9057 g_object_set_data(G_OBJECT(window), "_dw_defaultitem", (gpointer)defaultitem);
9058 }
9059
9060 /*
9061 * Sets window to click the default dialog item when an ENTER is pressed.
9062 * Parameters:
9063 * window: Window (widget) to look for the ENTER press.
9064 * next: Window (widget) to move to next (or click)
9065 */
9066 void dw_window_click_default(HWND window, HWND next)
9067 {
9068 if(!window)
9069 return;
9070
9071 g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(_default_key_press_event), next);
9072 }
9073
9074
9075 /*
9076 * Creates a new system notification if possible.
9077 * Parameters:
9078 * title: The short title of the notification.
9079 * imagepath: Path to an image to display or NULL if none.
9080 * description: A longer description of the notification,
9081 * or NULL if none is necessary.
9082 * Returns:
9083 * A handle to the notification which can be used to attach a "clicked" event if desired,
9084 * or NULL if it fails or notifications are not supported by the system.
9085 * Remarks:
9086 * This will create a system notification that will show in the notifaction panel
9087 * on supported systems, which may be clicked to perform another task.
9088 */
9089 HWND dw_notification_new(const char *title, const char *imagepath, const char *description, ...)
9090 {
9091 GNotification *notification = g_notification_new(title);
9092
9093 if(notification)
9094 {
9095 if(description)
9096 {
9097 va_list args;
9098 char outbuf[1025] = {0};
9099
9100 va_start(args, description);
9101 vsnprintf(outbuf, 1024, description, args);
9102 va_end(args);
9103
9104 g_notification_set_body(notification, outbuf);
9105 }
9106 if(imagepath)
9107 {
9108 GFile *file = g_file_new_for_path(imagepath);
9109 GBytes *bytes = g_file_load_bytes(file, NULL, NULL, NULL);
9110
9111 if(bytes)
9112 {
9113 GIcon *icon = g_bytes_icon_new(bytes);
9114
9115 if(icon)
9116 g_notification_set_icon(notification, G_ICON(icon));
9117 }
9118 }
9119 g_notification_set_default_action_and_target(notification, "app.notification", "t",
9120 (guint64)DW_POINTER_TO_ULONGLONG(notification));
9121 }
9122 return (HWND)notification;
9123 }
9124
9125 /*
9126 * Sends a notification created by dw_notification_new() after attaching signal handler.
9127 * Parameters:
9128 * notification: The handle to the notification returned by dw_notification_new().
9129 * Returns:
9130 * DW_ERROR_NONE on success, DW_ERROR_UNKNOWN on error or not supported.
9131 */
9132 int dw_notification_send(HWND notification)
9133 {
9134 if(notification)
9135 {
9136 char id[101] = {0};
9137
9138 /* Generate a unique ID based on the notification handle,
9139 * so we can use it to remove the notification in dw_window_destroy().
9140 */
9141 snprintf(id, 100, "dw-notification-%llu", DW_POINTER_TO_ULONGLONG(notification));
9142 g_application_send_notification(_DWApp, id, (GNotification *)notification);
9143 return DW_ERROR_NONE;
9144 }
9145 return DW_ERROR_UNKNOWN;
9146 }
9147
9148 /*
9149 * Returns some information about the current operating environment.
9150 * Parameters:
9151 * env: Pointer to a DWEnv struct.
9152 */
9153 void dw_environment_query(DWEnv *env)
9154 {
9155 struct utsname name;
9156 char tempbuf[_DW_ENV_STRING_SIZE] = { 0 }, *dot;
9157
9158 uname(&name);
9159 memset(env, '\0', sizeof(DWEnv));
9160 strncpy(env->osName, name.sysname, sizeof(env->osName)-1);
9161 strncpy(tempbuf, name.release, sizeof(tempbuf)-1);
9162
9163 strncpy(env->buildDate, __DATE__, sizeof(env->buildDate)-1);
9164 strncpy(env->buildTime, __TIME__, sizeof(env->buildTime)-1);
9165 #ifdef USE_WEBKIT
9166 strncpy(env->htmlEngine, "WEBKIT2", sizeof(env->htmlEngine)-1);
9167 #else
9168 strncpy(env->htmlEngine, "N/A", sizeof(env->htmlEngine)-1);
9169 #endif
9170 env->DWMajorVersion = DW_MAJOR_VERSION;
9171 env->DWMinorVersion = DW_MINOR_VERSION;
9172 #ifdef VER_REV
9173 env->DWSubVersion = VER_REV;
9174 #else
9175 env->DWSubVersion = DW_SUB_VERSION;
9176 #endif
9177
9178 if((dot = strchr(tempbuf, '.')) != NULL)
9179 {
9180 *dot = '\0';
9181 env->MajorVersion = atoi(tempbuf);
9182 env->MinorVersion = atoi(&dot[1]);
9183 return;
9184 }
9185 env->MajorVersion = atoi(tempbuf);
9186 }
9187
9188 /*
9189 * Opens a file dialog and queries user selection.
9190 * Parameters:
9191 * title: Title bar text for dialog.
9192 * defpath: The default path of the open dialog.
9193 * ext: Default file extention.
9194 * flags: DW_FILE_OPEN or DW_FILE_SAVE or DW_DIRECTORY_OPEN
9195 * Returns:
9196 * NULL on error. A malloced buffer containing
9197 * the file path on success.
9198 *
9199 */
9200 char *dw_file_browse(const char *title, const char *defpath, const char *ext, int flags)
9201 {
9202 GtkWidget *filew;
9203
9204 GtkFileChooserAction action;
9205 GtkFileFilter *filter1 = NULL;
9206 GtkFileFilter *filter2 = NULL;
9207 gchar *button;
9208 char *filename = NULL;
9209 char buf[1000];
9210 char mypath[PATH_MAX+1];
9211
9212 switch (flags )
9213 {
9214 case DW_DIRECTORY_OPEN:
9215 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
9216 button = _("_Open");
9217 break;
9218 case DW_FILE_OPEN:
9219 action = GTK_FILE_CHOOSER_ACTION_OPEN;
9220 button = _("_Open");
9221 break;
9222 case DW_FILE_SAVE:
9223 action = GTK_FILE_CHOOSER_ACTION_SAVE;
9224 button = _("_Save");
9225 break;
9226 default:
9227 dw_messagebox( "Coding error", DW_MB_OK|DW_MB_ERROR, "dw_file_browse() flags argument invalid.");
9228 return NULL;
9229 break;
9230 }
9231
9232 filew = gtk_file_chooser_dialog_new ( title,
9233 NULL,
9234 action,
9235 _("_Cancel"), GTK_RESPONSE_CANCEL,
9236 button, GTK_RESPONSE_ACCEPT,
9237 NULL);
9238
9239 if ( flags == DW_FILE_SAVE )
9240 gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER( filew ), TRUE );
9241
9242 if ( ext )
9243 {
9244 filter1 = gtk_file_filter_new();
9245 sprintf( buf, "*.%s", ext );
9246 gtk_file_filter_add_pattern( filter1, (gchar *)buf );
9247 sprintf( buf, "\"%s\" files", ext );
9248 gtk_file_filter_set_name( filter1, (gchar *)buf );
9249 filter2 = gtk_file_filter_new();
9250 gtk_file_filter_add_pattern( filter2, (gchar *)"*" );
9251 gtk_file_filter_set_name( filter2, (gchar *)"All Files" );
9252 gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( filew ), filter1 );
9253 gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( filew ), filter2 );
9254 }
9255
9256 if ( defpath )
9257 {
9258 struct stat buf;
9259
9260 if ( g_path_is_absolute( defpath ) || !realpath(defpath, mypath))
9261 {
9262 strcpy( mypath, defpath );
9263 }
9264
9265 /* See if the path exists */
9266 if(stat(mypath, &buf) == 0)
9267 {
9268 /* If the path is a directory... set the current folder */
9269 if(buf.st_mode & S_IFDIR)
9270 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( filew ), mypath );
9271 else if(flags == DW_FILE_SAVE) /* Otherwise set the filename */
9272 gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( filew ), mypath );
9273 else if(flags == DW_FILE_OPEN)
9274 gtk_file_chooser_select_filename( GTK_FILE_CHOOSER( filew), mypath );
9275 }
9276 else if(flags == DW_FILE_SAVE)
9277 {
9278 if(strchr(mypath, '/'))
9279 {
9280 unsigned long x = strlen(mypath) - 1;
9281
9282 /* Trim off the filename */
9283 while(x > 0 && mypath[x] != '/')
9284 {
9285 x--;
9286 }
9287 if(mypath[x] == '/')
9288 {
9289 char *file = NULL;
9290 char temp[PATH_MAX+1];
9291
9292 /* Save the original path in temp */
9293 strcpy(temp, mypath);
9294 mypath[x] = 0;
9295
9296 /* Check to make sure the trimmed piece is a directory */
9297 if(realpath(mypath, temp) && stat(temp, &buf) == 0)
9298 {
9299 if(buf.st_mode & S_IFDIR)
9300 {
9301 /* We now have it split */
9302 file = &mypath[x+1];
9303 }
9304 }
9305
9306 /* Select folder... */
9307 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(filew), temp );
9308 /* ... and file separately */
9309 if(file)
9310 gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER(filew), file );
9311 }
9312 }
9313 }
9314 }
9315
9316 if ( gtk_dialog_run( GTK_DIALOG( filew ) ) == GTK_RESPONSE_ACCEPT )
9317 {
9318 filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( filew ) );
9319 /*g_free (filename);*/
9320 }
9321
9322 gtk_widget_destroy( filew );
9323 return filename;
9324 }
9325
9326
9327 /*
9328 * Execute and external program in a seperate session.
9329 * Parameters:
9330 * program: Program name with optional path.
9331 * type: Either DW_EXEC_CON or DW_EXEC_GUI.
9332 * params: An array of pointers to string arguements.
9333 * Returns:
9334 * -1 on error.
9335 */
9336 int dw_exec(const char *program, int type, char **params)
9337 {
9338 int ret = -1;
9339
9340 if((ret = fork()) == 0)
9341 {
9342 int i;
9343
9344 for (i = 3; i < 256; i++)
9345 close(i);
9346 setsid();
9347 if(type == DW_EXEC_GUI)
9348 {
9349 execvp(program, params);
9350 }
9351 else if(type == DW_EXEC_CON)
9352 {
9353 char **tmpargs;
9354
9355 if(!params)
9356 {
9357 tmpargs = malloc(sizeof(char *));
9358 tmpargs[0] = NULL;
9359 }
9360 else
9361 {
9362 int z = 0;
9363
9364 while(params[z])
9365 {
9366 z++;
9367 }
9368 tmpargs = malloc(sizeof(char *)*(z+3));
9369 z=0;
9370 tmpargs[0] = "xterm";
9371 tmpargs[1] = "-e";
9372 while(params[z])
9373 {
9374 tmpargs[z+2] = params[z];
9375 z++;
9376 }
9377 tmpargs[z+2] = NULL;
9378 }
9379 execvp("xterm", tmpargs);
9380 free(tmpargs);
9381 }
9382 /* If we got here exec failed */
9383 _exit(-1);
9384 }
9385 return ret;
9386 }
9387
9388 /*
9389 * Loads a web browser pointed at the given URL.
9390 * Parameters:
9391 * url: Uniform resource locator.
9392 */
9393 int dw_browse(const char *url)
9394 {
9395 /* If possible load the URL/URI using gvfs... */
9396 #if GTK_CHECK_VERSION(3,22,0)
9397 if(gtk_show_uri_on_window(NULL, url, GDK_CURRENT_TIME, NULL))
9398 #else
9399 if(gtk_show_uri(gdk_screen_get_default(), url, GDK_CURRENT_TIME, NULL))
9400 #endif
9401 {
9402 return DW_ERROR_NONE;
9403 }
9404 else
9405 {
9406 /* Otherwise just fall back to executing firefox...
9407 * or the browser defined by the DW_BROWSER variable.
9408 */
9409 char *execargs[3], *browser = "firefox", *tmp;
9410
9411 tmp = getenv( "DW_BROWSER" );
9412 if(tmp) browser = tmp;
9413 execargs[0] = browser;
9414 execargs[1] = (char *)url;
9415 execargs[2] = NULL;
9416
9417 return dw_exec(browser, DW_EXEC_GUI, execargs);
9418 }
9419 }
9420
9421 #ifdef USE_WEBKIT
9422 /* Helper function to get the web view handle */
9423 WebKitWebView *_dw_html_web_view(GtkWidget *widget)
9424 {
9425 if(widget)
9426 {
9427 WebKitWebView *web_view = (WebKitWebView *)widget;
9428 if(WEBKIT_IS_WEB_VIEW(web_view))
9429 return web_view;
9430 #ifndef USE_WEBKIT2
9431 web_view = (WebKitWebView *)g_object_get_data(G_OBJECT(widget), "_dw_web_view");
9432 if(WEBKIT_IS_WEB_VIEW(web_view))
9433 return web_view;
9434 #endif
9435 }
9436 return NULL;
9437 }
9438 #endif
9439 /*
9440 * Causes the embedded HTML widget to take action.
9441 * Parameters:
9442 * handle: Handle to the window.
9443 * action: One of the DW_HTML_* constants.
9444 */
9445 void dw_html_action(HWND handle, int action)
9446 {
9447 #ifdef USE_WEBKIT
9448 WebKitWebView *web_view;
9449
9450 if((web_view = _dw_html_web_view(handle)))
9451 {
9452 switch(action)
9453 {
9454 case DW_HTML_GOBACK:
9455 webkit_web_view_go_back(web_view);
9456 break;
9457 case DW_HTML_GOFORWARD:
9458 webkit_web_view_go_forward(web_view);
9459 break;
9460 case DW_HTML_GOHOME:
9461 webkit_web_view_load_uri(web_view, DW_HOME_URL);
9462 break;
9463 case DW_HTML_RELOAD:
9464 webkit_web_view_reload(web_view);
9465 break;
9466 case DW_HTML_STOP:
9467 webkit_web_view_stop_loading(web_view);
9468 break;
9469 case DW_HTML_PRINT:
9470 {
9471 WebKitPrintOperation *operation = webkit_print_operation_new(web_view);
9472 webkit_print_operation_run_dialog(operation, NULL);
9473 g_object_unref(operation);
9474 }
9475 break;
9476 }
9477 }
9478 #endif
9479 }
9480
9481 /*
9482 * Render raw HTML code in the embedded HTML widget..
9483 * Parameters:
9484 * handle: Handle to the window.
9485 * string: String buffer containt HTML code to
9486 * be rendered.
9487 * Returns:
9488 * 0 on success.
9489 */
9490 int dw_html_raw(HWND handle, const char *string)
9491 {
9492 #ifdef USE_WEBKIT
9493 WebKitWebView *web_view;
9494
9495 if((web_view = _dw_html_web_view(handle)))
9496 {
9497 webkit_web_view_load_html(web_view, string, "file:///");
9498 gtk_widget_show(GTK_WIDGET(handle));
9499 }
9500 return DW_ERROR_NONE;
9501 #else
9502 return DW_ERROR_UNKNOWN;
9503 #endif
9504 }
9505
9506 /*
9507 * Render file or web page in the embedded HTML widget..
9508 * Parameters:
9509 * handle: Handle to the window.
9510 * url: Universal Resource Locator of the web or
9511 * file object to be rendered.
9512 * Returns:
9513 * 0 on success.
9514 */
9515 int dw_html_url(HWND handle, const char *url)
9516 {
9517 #ifdef USE_WEBKIT
9518 WebKitWebView *web_view;
9519
9520 if((web_view = _dw_html_web_view(handle)))
9521 {
9522 webkit_web_view_load_uri(web_view, url);
9523 gtk_widget_show(GTK_WIDGET(handle));
9524 }
9525 return DW_ERROR_NONE;
9526 #else
9527 return DW_ERROR_UNKNOWN;
9528 #endif
9529 }
9530
9531 /*
9532 * Executes the javascript contained in "script" in the HTML window.
9533 * Parameters:
9534 * handle: Handle to the HTML window.
9535 * script: Javascript code to execute.
9536 * scriptdata: Data passed to the signal handler.
9537 * Notes: A DW_SIGNAL_HTML_RESULT event will be raised with scriptdata.
9538 * Returns:
9539 * DW_ERROR_NONE (0) on success.
9540 */
9541 int dw_html_javascript_run(HWND handle, const char *script, void *scriptdata)
9542 {
9543 #ifdef USE_WEBKIT
9544 WebKitWebView *web_view;
9545
9546 if((web_view = _dw_html_web_view(handle)))
9547 webkit_web_view_run_javascript(web_view, script, NULL, _html_result_event, scriptdata);
9548 return DW_ERROR_NONE;
9549 #else
9550 return DW_ERROR_UNKNOWN;
9551 #endif
9552 }
9553
9554 /*
9555 * Create a new HTML window (widget) to be packed.
9556 * Parameters:
9557 * id: An ID to be used with dw_window_from_id() or 0L.
9558 */
9559 HWND dw_html_new(unsigned long id)
9560 {
9561 GtkWidget *widget = NULL;
9562 #ifdef USE_WEBKIT
9563 WebKitWebView *web_view;
9564 WebKitSettings *settings;
9565
9566 web_view = (WebKitWebView *)webkit_web_view_new();
9567 settings = webkit_web_view_get_settings(web_view);
9568 /* Make sure java script is enabled */
9569 webkit_settings_set_enable_javascript(settings, TRUE);
9570 webkit_web_view_set_settings(web_view, settings);
9571 widget = (GtkWidget *)web_view;
9572 gtk_widget_show(widget);
9573 #else
9574 dw_debug( "HTML widget not available; you do not have access to webkit.\n" );
9575 #endif
9576 return widget;
9577 }
9578
9579 /*
9580 * Gets the contents of the default clipboard as text.
9581 * Parameters:
9582 * None.
9583 * Returns:
9584 * Pointer to an allocated string of text or NULL if clipboard empty or contents could not
9585 * be converted to text.
9586 */
9587 char *dw_clipboard_get_text()
9588 {
9589 GtkClipboard *clipboard_object;
9590 char *ret = NULL;
9591
9592 if((clipboard_object = gtk_clipboard_get( GDK_SELECTION_CLIPBOARD )))
9593 {
9594 gchar *clipboard_contents;
9595
9596 if((clipboard_contents = gtk_clipboard_wait_for_text( clipboard_object )))
9597 {
9598 ret = strdup((char *)clipboard_contents);
9599 g_free(clipboard_contents);
9600 }
9601 }
9602 return ret;
9603 }
9604
9605 /*
9606 * Sets the contents of the default clipboard to the supplied text.
9607 * Parameters:
9608 * Text.
9609 */
9610 void dw_clipboard_set_text(const char *str, int len)
9611 {
9612 GtkClipboard *clipboard_object;
9613
9614 if((clipboard_object = gtk_clipboard_get( GDK_SELECTION_CLIPBOARD )))
9615 {
9616 gtk_clipboard_set_text( clipboard_object, str, len );
9617 }
9618 }
9619
9620 /* Internal function to create the drawable pixmap and call the function */
9621 static void _dw_draw_page(GtkPrintOperation *operation, GtkPrintContext *context, int page_nr)
9622 {
9623 cairo_t *cr = gtk_print_context_get_cairo_context(context);
9624 void *drawdata = g_object_get_data(G_OBJECT(operation), "_dw_drawdata");
9625 int (*drawfunc)(HPRINT, HPIXMAP, int, void *) = g_object_get_data(G_OBJECT(operation), "_dw_drawfunc");
9626 int result = 0;
9627 HPIXMAP pixmap;
9628
9629 if(cr && drawfunc && (pixmap = calloc(1,sizeof(struct _hpixmap))))
9630 {
9631 pixmap->image = cairo_get_group_target(cr);
9632 pixmap->handle = (HWND)operation;
9633 pixmap->width = gtk_print_context_get_width(context);
9634 pixmap->height = gtk_print_context_get_height(context);
9635 result = drawfunc((HPRINT)operation, pixmap, page_nr, drawdata);
9636 if(result)
9637 gtk_print_operation_draw_page_finish(operation);
9638 free(pixmap);
9639 }
9640 }
9641
9642 /*
9643 * Creates a new print object.
9644 * Parameters:
9645 * jobname: Name of the print job to show in the queue.
9646 * flags: Flags to initially configure the print object.
9647 * pages: Number of pages to print.
9648 * drawfunc: The pointer to the function to be used as the callback.
9649 * drawdata: User data to be passed to the handler function.
9650 * Returns:
9651 * A handle to the print object or NULL on failure.
9652 */
9653 HPRINT API dw_print_new(const char *jobname, unsigned long flags, unsigned int pages, void *drawfunc, void *drawdata)
9654 {
9655 GtkPrintOperation *op;
9656
9657 if(!drawfunc)
9658 return NULL;
9659
9660 if((op = gtk_print_operation_new()))
9661 {
9662 gtk_print_operation_set_n_pages(op, pages);
9663 gtk_print_operation_set_job_name(op, jobname ? jobname : "Dynamic Windows Print Job");
9664 g_object_set_data(G_OBJECT(op), "_dw_drawfunc", drawfunc);
9665 g_object_set_data(G_OBJECT(op), "_dw_drawdata", drawdata);
9666 g_signal_connect(op, "draw_page", G_CALLBACK(_dw_draw_page), NULL);
9667 }
9668 return (HPRINT)op;
9669 }
9670
9671 /*
9672 * Runs the print job, causing the draw page callbacks to fire.
9673 * Parameters:
9674 * print: Handle to the print object returned by dw_print_new().
9675 * flags: Flags to run the print job.
9676 * Returns:
9677 * DW_ERROR_UNKNOWN on error or DW_ERROR_NONE on success.
9678 */
9679 int API dw_print_run(HPRINT print, unsigned long flags)
9680 {
9681 GtkPrintOperationResult res;
9682 GtkPrintOperation *op = (GtkPrintOperation *)print;
9683
9684 res = gtk_print_operation_run(op, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, NULL, NULL);
9685 return (res == GTK_PRINT_OPERATION_RESULT_ERROR ? DW_ERROR_UNKNOWN : DW_ERROR_NONE);
9686 }
9687
9688 /*
9689 * Cancels the print job, typically called from a draw page callback.
9690 * Parameters:
9691 * print: Handle to the print object returned by dw_print_new().
9692 */
9693 void API dw_print_cancel(HPRINT print)
9694 {
9695 GtkPrintOperation *op = (GtkPrintOperation *)print;
9696
9697 gtk_print_operation_cancel(op);
9698 }
9699
9700 /*
9701 * Returns a pointer to a static buffer which contains the
9702 * current user directory. Or the root directory (C:\ on
9703 * OS/2 and Windows).
9704 */
9705 char *dw_user_dir(void)
9706 {
9707 static char _user_dir[1024] = "";
9708
9709 if(!_user_dir[0])
9710 {
9711 char *home = getenv("HOME");
9712
9713 if(home)
9714 strcpy(_user_dir, home);
9715 else
9716 strcpy(_user_dir, "/");
9717 }
9718 return _user_dir;
9719 }
9720
9721 /*
9722 * Returns a pointer to a static buffer which containes the
9723 * private application data directory.
9724 */
9725 char * API dw_app_dir(void)
9726 {
9727 return _dw_share_path;
9728 }
9729
9730 /*
9731 * Sets the application ID used by this Dynamic Windows application instance.
9732 * Parameters:
9733 * appid: A string typically in the form: com.company.division.application
9734 * appname: The application name used on Windows or NULL.
9735 * Returns:
9736 * DW_ERROR_NONE after successfully setting the application ID.
9737 * DW_ERROR_UNKNOWN if unsupported on this system.
9738 * DW_ERROR_GENERAL if the application ID is not allowed.
9739 * Remarks:
9740 * This must be called before dw_init(). If dw_init() is called first
9741 * it will create a unique ID in the form: org.dbsoft.dwindows.application
9742 * or if the application name cannot be detected: org.dbsoft.dwindows.pid.#
9743 * The appname is only required on Windows. If NULL is passed the detected
9744 * application name will be used, but a prettier name may be desired.
9745 */
9746 int dw_app_id_set(const char *appid, const char *appname)
9747 {
9748 #if GLIB_CHECK_VERSION(2,28,0)
9749 if(g_application_id_is_valid(appid))
9750 {
9751 strncpy(_dw_app_id, appid, _DW_APP_ID_SIZE);
9752 return DW_ERROR_NONE;
9753 }
9754 return DW_ERROR_GENERAL;
9755 #else
9756 return DW_ERROR_UNKNOWN;
9757 #endif
9758 }
9759
9760 /*
9761 * Call a function from the window (widget)'s context.
9762 * Parameters:
9763 * handle: Window handle of the widget.
9764 * function: Function pointer to be called.
9765 * data: Pointer to the data to be passed to the function.
9766 */
9767 void dw_window_function(HWND handle, void *function, void *data)
9768 {
9769 void (* windowfunc)(void *);
9770
9771 windowfunc = function;
9772
9773 if(windowfunc)
9774 windowfunc(data);
9775 }
9776
9777 /*
9778 * Add a named user data item to a window handle.
9779 * Parameters:
9780 * window: Window handle of signal to be called back.
9781 * dataname: A string pointer identifying which signal to be hooked.
9782 * data: User data to be passed to the handler function.
9783 */
9784 void dw_window_set_data(HWND window, const char *dataname, void *data)
9785 {
9786 HWND thiswindow = window;
9787
9788 if(!window)
9789 return;
9790
9791 if(GTK_IS_SCROLLED_WINDOW(window))
9792 {
9793 thiswindow = (HWND)g_object_get_data(G_OBJECT(window), "_dw_user");
9794 }
9795 if(thiswindow && G_IS_OBJECT(thiswindow))
9796 g_object_set_data(G_OBJECT(thiswindow), dataname, (gpointer)data);
9797 }
9798
9799 /*
9800 * Gets a named user data item to a window handle.
9801 * Parameters:
9802 * window: Window handle of signal to be called back.
9803 * dataname: A string pointer identifying which signal to be hooked.
9804 * data: User data to be passed to the handler function.
9805 */
9806 void *dw_window_get_data(HWND window, const char *dataname)
9807 {
9808 HWND thiswindow = window;
9809 void *ret = NULL;
9810
9811 if(!window)
9812 return NULL;
9813
9814 if(GTK_IS_SCROLLED_WINDOW(window))
9815 {
9816 thiswindow = (HWND)g_object_get_data(G_OBJECT(window), "_dw_user");
9817 }
9818 if(G_IS_OBJECT(thiswindow))
9819 ret = (void *)g_object_get_data(G_OBJECT(thiswindow), dataname);
9820 return ret;
9821 }
9822
9823 /* Internal function to get the state of the timer before firing */
9824 gboolean _dw_timer_func(gpointer data)
9825 {
9826 void (*sigfunc)(void *data) = NULL;
9827 void *sdata;
9828 char tmpbuf[31] = {0};
9829 int *tag = data;
9830
9831 if(tag)
9832 {
9833 snprintf(tmpbuf, 30, "_dw_timer%d", *tag);
9834 sigfunc = g_object_get_data(G_OBJECT(_DWObject), tmpbuf);
9835 snprintf(tmpbuf, 30, "_dw_timerdata%d", *tag);
9836 sdata = g_object_get_data(G_OBJECT(_DWObject), tmpbuf);
9837 }
9838 if(!sigfunc)
9839 {
9840 if(tag)
9841 free(tag);
9842 return FALSE;
9843 }
9844 sigfunc(sdata);
9845 return TRUE;
9846 }
9847
9848 /*
9849 * Add a callback to a timer event.
9850 * Parameters:
9851 * interval: Milliseconds to delay between calls.
9852 * sigfunc: The pointer to the function to be used as the callback.
9853 * data: User data to be passed to the handler function.
9854 * Returns:
9855 * Timer ID for use with dw_timer_disconnect(), 0 on error.
9856 */
9857 int API dw_timer_connect(int interval, void *sigfunc, void *data)
9858 {
9859 int *tag;
9860 char tmpbuf[31] = {0};
9861
9862 tag = calloc(1, sizeof(int));
9863
9864 *tag = g_timeout_add(interval, (GSourceFunc)_dw_timer_func, (gpointer)tag);
9865 snprintf(tmpbuf, 30, "_dw_timer%d", *tag);
9866 g_object_set_data(G_OBJECT(_DWObject), tmpbuf, sigfunc);
9867 snprintf(tmpbuf, 30, "_dw_timerdata%d", *tag);
9868 g_object_set_data(G_OBJECT(_DWObject), tmpbuf, data);
9869 return *tag;
9870 }
9871
9872 /*
9873 * Removes timer callback.
9874 * Parameters:
9875 * id: Timer ID returned by dw_timer_connect().
9876 */
9877 void API dw_timer_disconnect(int id)
9878 {
9879 char tmpbuf[31] = {0};
9880
9881 snprintf(tmpbuf, 30, "_dw_timer%d", id);
9882 g_object_set_data(G_OBJECT(_DWObject), tmpbuf, NULL);
9883 snprintf(tmpbuf, 30, "_dw_timerdata%d", id);
9884 g_object_set_data(G_OBJECT(_DWObject), tmpbuf, NULL);
9885 }
9886
9887 /* Get the actual signal window handle not the user window handle
9888 * Should mimic the code in dw_signal_connect() below.
9889 */
9890 static HWND _find_signal_window(HWND window, const char *signame)
9891 {
9892 HWND thiswindow = window;
9893
9894 if(GTK_IS_SCROLLED_WINDOW(thiswindow))
9895 thiswindow = (HWND)g_object_get_data(G_OBJECT(window), "_dw_user");
9896 else if(GTK_IS_SCALE(thiswindow) || GTK_IS_SCROLLBAR(thiswindow) || GTK_IS_SPIN_BUTTON(thiswindow))
9897 thiswindow = (GtkWidget *)g_object_get_data(G_OBJECT(thiswindow), "_dw_adjustment");
9898 else if(GTK_IS_TREE_VIEW(thiswindow) && strcmp(signame, DW_SIGNAL_ITEM_SELECT) == 0)
9899 thiswindow = (GtkWidget *)gtk_tree_view_get_selection(GTK_TREE_VIEW(thiswindow));
9900 return thiswindow;
9901 }
9902
9903 /*
9904 * Add a callback to a window event.
9905 * Parameters:
9906 * window: Window handle of signal to be called back.
9907 * signame: A string pointer identifying which signal to be hooked.
9908 * sigfunc: The pointer to the function to be used as the callback.
9909 * data: User data to be passed to the handler function.
9910 */
9911 void dw_signal_connect(HWND window, const char *signame, void *sigfunc, void *data)
9912 {
9913 dw_signal_connect_data(window, signame, sigfunc, NULL, data);
9914 }
9915
9916 /* Internal function to free any allocated signal data..
9917 * and call any required function to free additional memory.
9918 */
9919 static void _dw_signal_disconnect(gpointer data, GClosure *closure)
9920 {
9921 if(data)
9922 {
9923 void **params = (void **)data;
9924 void (*discfunc)(HWND, void *) = params[1];
9925
9926 if(discfunc)
9927 {
9928 SignalHandler work = _get_signal_handler(data);
9929
9930 if(work.window)
9931 {
9932 discfunc(work.window, work.data);
9933 }
9934 }
9935 free(data);
9936 }
9937 }
9938
9939 #define _DW_INTERNAL_CALLBACK_PARAMS 4
9940
9941 /*
9942 * Add a callback to a window event with a closure callback.
9943 * Parameters:
9944 * window: Window handle of signal to be called back.
9945 * signame: A string pointer identifying which signal to be hooked.
9946 * sigfunc: The pointer to the function to be used as the callback.
9947 * discfunc: The pointer to the function called when this handler is removed.
9948 * data: User data to be passed to the handler function.
9949 */
9950 void dw_signal_connect_data(HWND window, const char *signame, void *sigfunc, void *discfunc, void *data)
9951 {
9952 void *thisfunc = _findsigfunc(signame);
9953 char *thisname = (char *)signame;
9954 HWND thiswindow = window;
9955 int sigid;
9956 void **params = calloc(_DW_INTERNAL_CALLBACK_PARAMS, sizeof(void *));
9957 gint cid;
9958
9959 /* Save the disconnect function pointer */
9960 params[1] = discfunc;
9961
9962 /* Special case for handling notification signals, which aren't really signals */
9963 if (G_IS_NOTIFICATION(thiswindow) && strcmp(signame, DW_SIGNAL_CLICKED) == 0)
9964 {
9965 char textbuf[101] = {0};
9966 snprintf(textbuf, 100, "dw-notification-%llu-func", DW_POINTER_TO_ULONGLONG(thiswindow));
9967 g_object_set_data(G_OBJECT(_DWApp), textbuf, DW_POINTER(sigfunc));
9968 snprintf(textbuf, 100, "dw-notification-%llu-data", DW_POINTER_TO_ULONGLONG(thiswindow));
9969 g_object_set_data(G_OBJECT(_DWApp), textbuf, DW_POINTER(data));
9970 return;
9971 }
9972 /*
9973 * If the window we are setting the signal on is a scrolled window we need to get
9974 * the "real" widget type. thiswindow is the "real" widget type
9975 */
9976 if (GTK_IS_SCROLLED_WINDOW(thiswindow)
9977 #ifdef USE_WEBKIT
9978 && !(thiswindow = (HWND)_dw_html_web_view(thiswindow))
9979 #endif
9980 )
9981 {
9982 thiswindow = (HWND)g_object_get_data(G_OBJECT(window), "_dw_user");
9983 }
9984
9985 if (strcmp(signame, DW_SIGNAL_EXPOSE) == 0)
9986 {
9987 thisname = "draw";
9988 }
9989 else if (GTK_IS_MENU_ITEM(thiswindow) && strcmp(signame, DW_SIGNAL_CLICKED) == 0)
9990 {
9991 thisname = "activate";
9992 thisfunc = _findsigfunc(thisname);
9993 }
9994 else if (GTK_IS_TREE_VIEW(thiswindow) && strcmp(signame, DW_SIGNAL_ITEM_CONTEXT) == 0)
9995 {
9996 sigid = _set_signal_handler(thiswindow, window, sigfunc, data, thisfunc, discfunc);
9997 params[0] = GINT_TO_POINTER(sigid);
9998 params[2] = (void *)thiswindow;
9999 cid = g_signal_connect_data(G_OBJECT(thiswindow), "button_press_event", G_CALLBACK(thisfunc), params, _dw_signal_disconnect, 0);
10000 _set_signal_handler_id(thiswindow, sigid, cid);
10001 return;
10002 }
10003 else if ((GTK_IS_TREE_VIEW(thiswindow) && strcmp(signame, DW_SIGNAL_ITEM_SELECT) == 0) ||
10004 (GTK_IS_COMBO_BOX(thiswindow) && strcmp(signame, DW_SIGNAL_LIST_SELECT) == 0))
10005 {
10006 GtkWidget *widget = thiswindow;
10007
10008 thisname = "changed";
10009
10010 sigid = _set_signal_handler(widget, window, sigfunc, data, thisfunc, discfunc);
10011 params[0] = GINT_TO_POINTER(sigid);
10012 params[2] = (void *)thiswindow;
10013 if(GTK_IS_TREE_VIEW(thiswindow))
10014 {
10015 thiswindow = (GtkWidget *)gtk_tree_view_get_selection(GTK_TREE_VIEW(thiswindow));
10016 cid = g_signal_connect_data(G_OBJECT(thiswindow), thisname, G_CALLBACK(thisfunc), params, _dw_signal_disconnect, 0);
10017 }
10018 else
10019 {
10020 cid = g_signal_connect_data(G_OBJECT(thiswindow), thisname, G_CALLBACK(_combobox_select_event), params, _dw_signal_disconnect, 0);
10021 }
10022 _set_signal_handler_id(widget, sigid, cid);
10023 return;
10024 }
10025 else if (GTK_IS_TREE_VIEW(thiswindow) && strcmp(signame, DW_SIGNAL_TREE_EXPAND) == 0)
10026 {
10027 thisname = "row-expanded";
10028 }
10029 else if (GTK_IS_TREE_VIEW(thiswindow) && strcmp(signame, DW_SIGNAL_ITEM_ENTER) == 0)
10030 {
10031 sigid = _set_signal_handler(thiswindow, window, sigfunc, data, _container_enter_event, discfunc);
10032 params[0] = GINT_TO_POINTER(sigid);
10033 params[2] = (void *)thiswindow;
10034 cid = g_signal_connect_data(G_OBJECT(thiswindow), "key_press_event", G_CALLBACK(_container_enter_event), params, _dw_signal_disconnect, 0);
10035 _set_signal_handler_id(thiswindow, sigid, cid);
10036
10037 params = calloc(sizeof(void *), _DW_INTERNAL_CALLBACK_PARAMS);
10038
10039 thisname = "button_press_event";
10040 thisfunc = _findsigfunc(DW_SIGNAL_ITEM_ENTER);
10041 }
10042 else if (GTK_IS_TREE_VIEW(thiswindow) && strcmp(signame, DW_SIGNAL_COLUMN_CLICK) == 0)
10043 {
10044 /* We don't actually need a signal handler here... just need to assign the handler ID
10045 * Since the handlers for the columns were already created in _dw_container_setup()
10046 */
10047 sigid = _set_signal_handler(thiswindow, window, sigfunc, data, _column_click_event, discfunc);
10048 g_object_set_data(G_OBJECT(thiswindow), "_dw_column_click_id", GINT_TO_POINTER(sigid+1));
10049 return;
10050 }
10051 else if (strcmp(signame, DW_SIGNAL_SET_FOCUS) == 0)
10052 {
10053 thisname = "focus-in-event";
10054 if (GTK_IS_COMBO_BOX(thiswindow))
10055 thiswindow = gtk_bin_get_child(GTK_BIN(thiswindow));
10056 }
10057 #ifdef USE_WEBKIT
10058 else if (WEBKIT_IS_WEB_VIEW(thiswindow) && strcmp(signame, DW_SIGNAL_HTML_CHANGED) == 0)
10059 {
10060 thisname = "load-changed";
10061 }
10062 else if (WEBKIT_IS_WEB_VIEW(thiswindow) && strcmp(signame, DW_SIGNAL_HTML_RESULT) == 0)
10063 {
10064 /* We don't actually need a signal handler here... just need to assign the handler ID
10065 * Since the handler is created in dw_html_javasript_run()
10066 */
10067 sigid = _set_signal_handler(thiswindow, window, sigfunc, data, _html_result_event, discfunc);
10068 g_object_set_data(G_OBJECT(thiswindow), "_dw_html_result_id", GINT_TO_POINTER(sigid+1));
10069 return;
10070 }
10071 #endif
10072 #if 0
10073 else if (strcmp(signame, DW_SIGNAL_LOSE_FOCUS) == 0)
10074 {
10075 thisname = "focus-out-event";
10076 if(GTK_IS_COMBO_BOX(thiswindow))
10077 thiswindow = GTK_COMBO_BOX(thiswindow)->entry;
10078 }
10079 #endif
10080 else if (GTK_IS_SCALE(thiswindow) || GTK_IS_SCROLLBAR(thiswindow) || GTK_IS_SPIN_BUTTON(thiswindow) )
10081 {
10082 thiswindow = (GtkWidget *)g_object_get_data(G_OBJECT(thiswindow), "_dw_adjustment");
10083 }
10084 else if (GTK_IS_NOTEBOOK(thiswindow) && strcmp(signame, DW_SIGNAL_SWITCH_PAGE) == 0)
10085 {
10086 thisname = "switch-page";
10087 }
10088
10089 if (!thisfunc || !thiswindow)
10090 {
10091 free(params);
10092 return;
10093 }
10094
10095 sigid = _set_signal_handler(thiswindow, window, sigfunc, data, thisfunc, discfunc);
10096 params[0] = GINT_TO_POINTER(sigid);
10097 params[2] = (void *)thiswindow;
10098 cid = g_signal_connect_data(G_OBJECT(thiswindow), thisname, G_CALLBACK(thisfunc), params, _dw_signal_disconnect, 0);
10099 _set_signal_handler_id(thiswindow, sigid, cid);
10100 }
10101
10102 /*
10103 * Removes callbacks for a given window with given name.
10104 * Parameters:
10105 * window: Window handle of callback to be removed.
10106 */
10107 void dw_signal_disconnect_by_name(HWND window, const char *signame)
10108 {
10109 int z, count;
10110 void *thisfunc;
10111 void **params = alloca(sizeof(void *) * 3);
10112
10113 params[2] = _find_signal_window(window, signame);
10114 count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(params[2]), "_dw_sigcounter"));
10115 thisfunc = _findsigfunc(signame);
10116
10117 for(z=0;z<count;z++)
10118 {
10119 SignalHandler sh;
10120
10121 params[0] = GINT_TO_POINTER(z);
10122 sh = _get_signal_handler(params);
10123
10124 if(sh.intfunc == thisfunc)
10125 _remove_signal_handler((HWND)params[2], z);
10126 }
10127 }
10128
10129 /*
10130 * Removes all callbacks for a given window.
10131 * Parameters:
10132 * window: Window handle of callback to be removed.
10133 */
10134 void dw_signal_disconnect_by_window(HWND window)
10135 {
10136 HWND thiswindow;
10137 int z, count;
10138
10139 thiswindow = _find_signal_window(window, NULL);
10140 count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(thiswindow), "_dw_sigcounter"));
10141
10142 for(z=0;z<count;z++)
10143 _remove_signal_handler(thiswindow, z);
10144 g_object_set_data(G_OBJECT(thiswindow), "_dw_sigcounter", NULL);
10145 }
10146
10147 /*
10148 * Removes all callbacks for a given window with specified data.
10149 * Parameters:
10150 * window: Window handle of callback to be removed.
10151 * data: Pointer to the data to be compared against.
10152 */
10153 void dw_signal_disconnect_by_data(HWND window, void *data)
10154 {
10155 int z, count;
10156 void **params = alloca(sizeof(void *) * 3);
10157
10158 params[2] = _find_signal_window(window, NULL);
10159 count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(params[2]), "_dw_sigcounter"));
10160
10161 for(z=0;z<count;z++)
10162 {
10163 SignalHandler sh;
10164
10165 params[0] = GINT_TO_POINTER(z);
10166 sh = _get_signal_handler(params);
10167
10168 if(sh.data == data)
10169 _remove_signal_handler((HWND)params[2], z);
10170 }
10171 }
10172
10173 /*
10174 * Converts a UTF-8 encoded string into a wide string.
10175 * Parameters:
10176 * utf8string: UTF-8 encoded source string.
10177 * Returns:
10178 * Wide string that needs to be freed with dw_free()
10179 * or NULL on failure.
10180 */
10181 wchar_t * API dw_utf8_to_wchar(const char *utf8string)
10182 {
10183 wchar_t *retval = NULL, *freeme;
10184
10185 if(sizeof(wchar_t) == sizeof(gunichar))
10186 freeme = retval = (wchar_t *)g_utf8_to_ucs4(utf8string, -1, NULL, NULL, NULL);
10187 else if(sizeof(wchar_t) == sizeof(gunichar2))
10188 freeme = retval = (wchar_t *)g_utf8_to_utf16(utf8string, -1, NULL, NULL, NULL);
10189 if(retval)
10190 {
10191 retval = wcsdup(retval);
10192 g_free(freeme);
10193 }
10194 return retval;
10195 }
10196
10197 /*
10198 * Converts a wide string into a UTF-8 encoded string.
10199 * Parameters:
10200 * wstring: Wide source string.
10201 * Returns:
10202 * UTF-8 encoded string that needs to be freed with dw_free()
10203 * or NULL on failure.
10204 */
10205 char * API dw_wchar_to_utf8(const wchar_t *wstring)
10206 {
10207 char *retval = NULL, *freeme;
10208
10209 if(sizeof(wchar_t) == sizeof(gunichar))
10210 freeme = retval = g_ucs4_to_utf8((gunichar *)wstring, -1, NULL, NULL, NULL);
10211 else if(sizeof(wchar_t) == sizeof(gunichar2))
10212 freeme = retval = g_utf16_to_utf8((gunichar2 *)wstring, -1, NULL, NULL, NULL);
10213 if(retval)
10214 {
10215 retval = strdup(retval);
10216 g_free(freeme);
10217 }
10218 return retval;
10219 }
10220
10221 /*
10222 * Gets the state of the requested library feature.
10223 * Parameters:
10224 * feature: The requested feature for example DW_FEATURE_DARK_MODE
10225 * Returns:
10226 * DW_FEATURE_UNSUPPORTED if the library or OS does not support the feature.
10227 * DW_FEATURE_DISABLED if the feature is supported but disabled.
10228 * DW_FEATURE_ENABLED if the feature is supported and enabled.
10229 * Other value greater than 1, same as enabled but with extra info.
10230 */
10231 int API dw_feature_get(DWFEATURE feature)
10232 {
10233 switch(feature)
10234 {
10235 #ifdef USE_WEBKIT
10236 case DW_FEATURE_HTML:
10237 case DW_FEATURE_HTML_RESULT:
10238 #endif
10239 case DW_FEATURE_NOTIFICATION:
10240 case DW_FEATURE_CONTAINER_STRIPE:
10241 case DW_FEATURE_UTF8_UNICODE:
10242 case DW_FEATURE_MLE_WORD_WRAP:
10243 return DW_FEATURE_ENABLED;
10244 default:
10245 return DW_FEATURE_UNSUPPORTED;
10246 }
10247 }
10248
10249 /*
10250 * Sets the state of the requested library feature.
10251 * Parameters:
10252 * feature: The requested feature for example DW_FEATURE_DARK_MODE
10253 * state: DW_FEATURE_DISABLED, DW_FEATURE_ENABLED or any value greater than 1.
10254 * Returns:
10255 * DW_FEATURE_UNSUPPORTED if the library or OS does not support the feature.
10256 * DW_ERROR_NONE if the feature is supported and successfully configured.
10257 * DW_ERROR_GENERAL if the feature is supported but could not be configured.
10258 * Remarks:
10259 * These settings are typically used during dw_init() so issue before
10260 * setting up the library with dw_init().
10261 */
10262 int API dw_feature_set(DWFEATURE feature, int state)
10263 {
10264 switch(feature)
10265 {
10266 /* These features are supported but not configurable */
10267 #ifdef USE_WEBKIT
10268 case DW_FEATURE_HTML:
10269 case DW_FEATURE_HTML_RESULT:
10270 #endif
10271 case DW_FEATURE_NOTIFICATION:
10272 case DW_FEATURE_CONTAINER_STRIPE:
10273 case DW_FEATURE_UTF8_UNICODE:
10274 case DW_FEATURE_MLE_WORD_WRAP:
10275 return DW_ERROR_GENERAL;
10276 /* These features are supported and configurable */
10277 default:
10278 return DW_FEATURE_UNSUPPORTED;
10279 }
10280 }
10281