Mercurial > dwindows
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(>kthread, 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 |