Jitterbug no more.
[fvwm.git] / modules / FvwmGtk / FvwmGtk.c
blob216d99768f0563d7a7e4fb74869c3049eef7fa14
1 /* -*-c-*- */
2 /*
3 * FvwmGtk - gtk menus and dialogs for fvwm
5 * Copyright (c) 1999 Matthias Clasen <clasen@mathematik.uni-freiburg.de>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "config.h"
24 #include <stdio.h>
25 #include <unistd.h>
27 #include <X11/Xlib.h>
29 #ifdef NEED_GNOMESUPPORT_H
30 #include <gnome.h>
31 #else
32 #include <glib.h>
33 #include <gtk/gtk.h>
34 #endif
36 #ifdef GDK_IMLIB
37 #include <gdk_imlib.h>
38 #endif
40 #include "libs/Module.h"
41 #include "libs/fvwmlib.h"
42 #include "fvwm/fvwm.h"
43 #include "libs/vpacket.h"
44 #include "libs/Parse.h"
45 #include "libs/Strings.h"
47 #include "dialog.h"
48 #include "menu.h"
49 #include "windowlist.h"
52 int fvwm_fd[2] = { -1, -1 };
53 static ModuleArgs *module;
54 char *image_path = NULL;
55 GHashTable *widgets = NULL;
56 GtkWidget *current = NULL;
57 GtkWidget *attach_to_toplevel = NULL;
58 unsigned long context = 0;
59 int icon_w = 0;
60 int icon_h = 0;
61 long current_desk = 0;
62 GHashTable *window_list_entries = NULL;
65 General overview:
67 All widgets (menus and dialogs) are stored in one hash table, widgets.
68 They are built up piecemeal, the widget currently being built up is current.
69 For dialogs, current may also point to a subwidget of the dialog.
71 dialog contain diffent kinds of widgets:
73 * data widgets which return some value these all have a name and store
74 their value as data on the top-level dialog under their name
76 * action widgets like buttons. These have a list of commands which are
77 sent to fvwm or executed by FvwmGtk itself (eg close).
78 The commands are stored as data on the action widget under the name
79 "values", as a NULL-terminated char*-array.
81 A command can contain references to other widgets values in the form
82 $(name). These references are resolved recursively, ie the values can
83 again contain references.
85 The resolution of the references is done by splitting the string into a
86 list of passive strings and variable references and splicing in sublists
87 for the variable references until only passive strings remain.
91 void destroy(int argc, char **argv)
93 GtkWidget *w;
95 g_return_if_fail(argc >= 1);
97 w = g_hash_table_lookup(widgets, argv[0]);
98 if (w != NULL)
100 if (gtk_widget_get_toplevel(current) == w)
102 current = NULL;
105 g_hash_table_remove(widgets, argv[0]);
106 gtk_object_unref(GTK_OBJECT(w));
107 gtk_widget_destroy(w);
112 void separator(int argc, char **argv)
114 if (GTK_IS_MENU(current))
116 menu_separator(argc, argv);
118 else
120 dialog_separator(argc, argv);
125 void item(int argc, char **argv)
127 if (GTK_IS_MENU(current))
129 menu_item(argc, argv);
131 else
133 dialog_option_menu_item(argc, argv);
138 void parse_rc_file(int argc, char **argv)
140 g_return_if_fail(argc >= 1);
142 gtk_rc_parse(argv[0]);
146 void icon_size(int argc, char **argv)
148 if (argc < 2)
150 icon_w = 0;
151 icon_h = 0;
153 else
155 icon_w = atoi(argv[0]);
156 icon_h = atoi(argv[1]);
161 char *table[] = {
162 "Box",
163 "Button",
164 "CheckButton",
165 "Color",
166 "Destroy",
167 "Dialog",
168 "EndBox",
169 "EndFrame",
170 "EndNotebook",
171 "EndOptionMenu",
172 "EndRadioGroup",
173 "Entry",
174 "Frame",
175 "IconSize",
176 "Item",
177 "Label",
178 "Menu",
179 "Notebook",
180 "OptionMenu",
181 "RadioButton",
182 "RadioGroup",
183 "RCFile",
184 "Scale",
185 "Separator",
186 "SpinButton",
187 "Submenu",
188 "Tearoff",
189 "Title",
190 "WindowList",
194 void (*handler[])(int, char**) = {
195 dialog_start_box,
196 dialog_button,
197 dialog_checkbutton,
198 dialog_color,
199 destroy,
200 open_dialog,
201 dialog_end_something,
202 dialog_end_something,
203 dialog_end_notebook,
204 dialog_end_option_menu,
205 dialog_end_radiogroup,
206 dialog_entry,
207 dialog_start_frame,
208 icon_size,
209 item,
210 dialog_label,
211 open_menu,
212 dialog_notebook,
213 dialog_start_option_menu,
214 dialog_radiobutton,
215 dialog_start_radiogroup,
216 parse_rc_file,
217 dialog_scale,
218 separator,
219 dialog_spinbutton,
220 menu_submenu,
221 menu_tearoff_item,
222 menu_title,
223 window_list
227 void parse_arguments(char **line, int *argc, char ***argv)
229 char *tmp[100];
230 int i;
232 for (i = 0; i < 100 ; i++)
234 *line = GetNextSimpleOption(*line, &tmp[i]);
235 if (!tmp[i]) break;
237 *argc = i;
239 *argv = (char **) safemalloc(i * sizeof(char *));
240 for (i = 0; i < *argc; i++)
242 (*argv)[i] = tmp[i];
247 void widget_not_found(char *name)
249 GtkWidget *dialog, *box, *item;
250 char buf[200];
252 SendText(fvwm_fd, "Beep", 0);
253 dialog = gtk_window_new(GTK_WINDOW_DIALOG);
254 gtk_window_set_title(GTK_WINDOW(dialog), "Error");
255 gtk_window_set_wmclass(GTK_WINDOW(dialog), "Error", "FvwmGtk");
257 box = gtk_vbox_new(FALSE, 10);
258 gtk_container_add(GTK_CONTAINER(dialog), box);
259 gtk_container_border_width(GTK_CONTAINER(dialog), 30);
260 g_snprintf(buf, sizeof(buf), "No such menu or dialog: %s", name);
261 item = gtk_label_new(buf);
262 gtk_box_pack_start(GTK_BOX(box), item, FALSE, FALSE, 5);
263 item = gtk_button_new_with_label("OK");
264 gtk_box_pack_start(GTK_BOX(box), item, FALSE, FALSE, 5);
265 gtk_signal_connect_object(
266 GTK_OBJECT(item), "clicked",
267 GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dialog));
268 gtk_widget_show_all(box);
269 gtk_widget_show(dialog);
273 void parse_config_line(char *buf)
275 int argc;
276 char **argv;
277 char *p;
278 char **e;
280 if (buf[strlen(buf)-1] == '\n')
282 buf[strlen(buf)-1] = '\0';
284 if (
285 strncasecmp(
286 buf, CatString3("*",module->name,0),
287 module->namelen+1) == 0)
289 p = buf + module->namelen+1;
290 if ((e = FindToken(p, table, char*)))
292 p += strlen(*e);
293 parse_arguments(&p, &argc, &argv);
294 handler[e - (char**)table](argc, argv);
296 else
298 fprintf(stderr, "%s: unknown command: %s\n",
299 module->name, buf);
302 else if (strncasecmp(buf, "ImagePath", 9) == 0)
304 if (image_path)
306 free(image_path);
308 image_path = stripcpy(buf + 9);
313 void parse_options(void)
315 char *buf;
317 /* only my config lines needed */
318 InitGetConfigLine(fvwm_fd,CatString3("*",module->name,0));
319 while (GetConfigLine(fvwm_fd, &buf), buf != NULL)
321 parse_config_line(buf);
326 void process_message(
327 unsigned long type, unsigned long timestamp, unsigned long *body)
329 int button = 0;
330 GtkWidget *widget;
331 window_list_options *opts;
333 char name[128];
335 switch (type)
337 case M_STRING:
338 SendUnlockNotification(fvwm_fd);
339 context = body[0]; /* this is fw */
340 sscanf((char*)(&body[3]), "%127s %d", name, &button);
341 widget = g_hash_table_lookup(widgets, name);
342 if (!widget)
344 widget_not_found(name);
346 else if (GTK_IS_MENU(widget))
348 opts = (window_list_options *)gtk_object_get_data(
349 GTK_OBJECT(widget), "window_list");
350 if (opts)
352 char *argv[1];
354 argv[0] = name;
355 destroy(1, argv);
356 open_menu(1, argv);
357 widget = current;
358 gtk_object_set_data(
359 GTK_OBJECT(current), "window_list",
360 opts);
361 construct_window_list();
364 gtk_menu_popup(
365 GTK_MENU(widget), NULL, NULL, NULL, NULL,
366 button, timestamp);
368 else if (GTK_IS_WINDOW(widget))
370 gtk_widget_show(GTK_WIDGET(widget));
372 break;
373 case M_CONFIG_INFO:
374 parse_config_line((char *)(&body[3]));
375 break;
376 case M_NEW_DESK:
377 current_desk = (long)body[0];
378 break;
379 case M_ADD_WINDOW:
380 case M_CONFIGURE_WINDOW:
382 struct ConfigWinPacket *cfg = (void *)body;
383 window_list_entry *wle =
384 lookup_window_list_entry(body[0]);
386 wle->desk = cfg->desk;
387 wle->layer = 0;
388 wle->iconified = IS_ICONIFIED(cfg);
389 wle->sticky = (IS_STICKY_ACROSS_PAGES(cfg) ||
390 IS_STICKY_ACROSS_DESKS(cfg));
391 wle->skip = DO_SKIP_WINDOW_LIST(cfg);
392 wle->x = cfg->frame_x;
393 wle->y = cfg->frame_y;
394 wle->width = cfg->frame_width;
395 wle->height = cfg->frame_height;
397 break;
398 case M_DESTROY_WINDOW:
399 g_hash_table_remove(window_list_entries, &(body[0]));
400 break;
401 case M_VISIBLE_NAME:
403 window_list_entry *wle =
404 lookup_window_list_entry(body[0]);
405 if (wle->name)
407 free(wle->name);
409 wle->name = safestrdup((char *)(&body[3]));
411 break;
412 case MX_VISIBLE_ICON_NAME:
414 window_list_entry *wle =
415 lookup_window_list_entry(body[0]);
416 if (wle->icon_name)
418 free(wle->icon_name);
420 wle->icon_name = safestrdup((char*)(&body[3]));
422 break;
423 case M_MINI_ICON:
426 MiniIconPacket *mip = (MiniIconPacket *)body;
427 window_list_entry *wle =
428 lookup_window_list_entry(mip->w);
430 if (wle->mini_icon)
432 free(wle->mini_icon);
434 wle->mini_icon = mip->name[0] != '\0' ?
435 safestrdup(mip->name) : NULL;
437 break;
442 void read_fvwm_pipe(gpointer data, int source, GdkInputCondition cond)
444 FvwmPacket* packet = ReadFvwmPacket(source);
445 if (packet == NULL)
447 exit(0);
449 else
451 process_message(packet->type, packet->timestamp, packet->body);
455 int main(int argc, char **argv)
457 module = ParseModuleArgs(argc,argv,1);
458 if (module == NULL)
460 fprintf(
461 stderr, "FvwmGtk version %s should only be executed by"
462 " fvwm!\n", VERSION);
463 exit(1);
466 fvwm_fd[0] = module->to_fvwm;
467 fvwm_fd[1] = module->from_fvwm;
469 #ifdef GDK_IMLIB
470 gdk_init(&argc, &argv);
471 gdk_imlib_init();
472 gtk_widget_push_visual(gdk_imlib_get_visual());
473 gtk_widget_push_colormap(gdk_imlib_get_colormap());
474 #endif
476 #ifdef NEED_GNOMESUPPORT_H
477 gnome_init("FvwmGtk", VERSION, argc, argv);
478 gnome_client_disconnect(gnome_master_client());
479 #else
480 gtk_init(&argc, &argv);
481 #endif
483 widgets = g_hash_table_new(g_str_hash, g_str_equal);
485 attach_to_toplevel = gtk_window_new(GTK_WINDOW_TOPLEVEL);
486 gtk_widget_realize(attach_to_toplevel);
488 window_list_entries = g_hash_table_new(g_int_hash, g_int_equal);
490 parse_options();
492 /* normal messages */
493 SetMessageMask(
494 fvwm_fd,
495 M_STRING |
496 M_CONFIG_INFO |
497 M_SENDCONFIG |
498 M_ADD_WINDOW |
499 M_DESTROY_WINDOW |
500 M_CONFIGURE_WINDOW |
501 M_NEW_DESK |
502 M_VISIBLE_NAME |
503 M_MINI_ICON);
504 /* extended messages */
505 SetMessageMask(
506 fvwm_fd,
507 MX_VISIBLE_ICON_NAME);
509 SendText(fvwm_fd, "Send_WindowList", 0);
511 gtk_input_add_full(
512 fvwm_fd[1], GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
513 read_fvwm_pipe, NULL, NULL, NULL);
515 /* tell fvwm we're running */
516 SendFinishedStartupNotification(fvwm_fd);
518 /* tell fvwm we want to be lock on send for M_STRING Messages */
519 SetSyncMask(fvwm_fd, M_STRING);
521 gtk_main();
522 return 0;