00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <gtk/gtk.h>
00033 #include <string.h>
00034
00035
00036 #include <libergtk/ergtk.h>
00037
00038
00039 #include "log.h"
00040 #include "menustore.h"
00041 #include "pixlist.h"
00042 #include "i18n.h"
00043 #include "ipc.h"
00044
00045
00046
00047
00048
00049 enum menu_type
00050 {
00051 MENU_TYPE_GROUP = 0,
00052 MENU_TYPE_ITEM,
00053 };
00054
00055 typedef struct
00056 {
00057 gchar* name;
00058 gchar* service;
00059 GList* groups;
00060 } MenuEntry;
00061
00062 typedef struct
00063 {
00064 const gchar* name;
00065 gboolean found;
00066 GtkTreeIter* iter;
00067 } SearchArgs;
00068
00069 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00070 typedef struct
00071 {
00072 const char* pname;
00073 const char* iname;
00074 } ToolItem;
00075
00076 typedef struct
00077 {
00078 const char* menu;
00079 ToolItem items[MENUSTORE_NUM_TOOLS];
00080 } MenuToolItems;
00081 #endif
00082
00083
00084
00085
00086
00087 GtkTreeStore *menu_store = NULL;
00088 static GList *menu_list = NULL;
00089 static gchar *current_menu = NULL;
00090 static taskbar_cb_t taskbar_home_cb = NULL;
00091 static gboolean g_popup_has_changed = FALSE;
00092 static gboolean g_toolbar_has_changed = FALSE;
00093
00094
00095
00096
00097
00098
00099 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00100 static MenuToolItems hardcoded_tools[] =
00101 {
00102 { "ctb_menu_content", {
00103 { "system_top", "desktop" },
00104 { "ctb_view", "view_small" },
00105 { "ctb_view", "view_detail" },
00106 { "ctb_view", "view_content" },
00107 } },
00108 { "ctb_menu_content_media", {
00109 { "system_top", "desktop" },
00110 { "ctb_view", "view_small" },
00111 { "ctb_view", "view_detail" },
00112 { "ctb_view", "view_content" },
00113 } },
00114 { "ctb_menu_recent_mode", {
00115 { "system_top", "desktop" },
00116 { "ctb_view", "view_small" },
00117 { "ctb_view", "view_detail" },
00118 { "ctb_view", "view_content" },
00119 } },
00120 { "ctb_menu_delete_mode", {
00121 { "system_top", "desktop" },
00122 { "ctb_view", "view_small" },
00123 { "ctb_view", "view_detail" },
00124 { "ctb_view", "view_content" },
00125 } },
00126 { "uds_menu_reading", {
00127 { "system_top", "desktop" },
00128 { "system_top", "back_to_library" },
00129 { "uds_navigation", "search_text" },
00130 { "uds_navigation", "goto_page" },
00131 { "pen_functions", "pen" },
00132 { "pen_functions", "eraser" },
00133 { "zoom_page", "mode_continuous" },
00134 { "zoom_shift", "zoom_fit" },
00135 { "zoom_shift", "zoom_selection" },
00136 { "zoom_shift", "mode_pan" },
00137 { "uds_views", "view_annotation" },
00138 { "uds_views", "view_toc" },
00139 { "uds_views", "view_thumbnail" },
00140 { "uds_navigation", "close" },
00141 } },
00142 { "uds_menu_annotation", {
00143 { "system_top", "desktop" },
00144 { "system_top", "back_to_library" },
00145 { "uds_views", "view_reading" },
00146 { "uds_views", "view_toc" },
00147 { "uds_views", "view_thumbnail" },
00148 } },
00149 { "uds_menu_toc", {
00150 { "system_top", "desktop" },
00151 { "system_top", "back_to_library" },
00152 { "uds_views", "view_reading" },
00153 { "uds_views", "view_annotation" },
00154 { "uds_views", "view_thumbnail" },
00155 } },
00156 { "uds_menu_thumbnail", {
00157 { "system_top", "desktop" },
00158 { "system_top", "back_to_library" },
00159 { "uds_views", "view_reading" },
00160 { "uds_views", "view_annotation" },
00161 { "uds_views", "view_thumbnail" },
00162 } },
00163 { "uds_menu_bookinfo", {
00164 { "system_top", "desktop" },
00165 { "system_top", "back_to_library" },
00166 { "uds_views", "view_reading" },
00167 { "uds_views", "view_annotation" },
00168 { "uds_views", "view_thumbnail" },
00169 } },
00170 { "notepad_menu", {
00171 { "system_top", "desktop" },
00172 { "notepad_actions", "clear_page" },
00173 { "notepad_actions", "insert_page" },
00174 { "notepad_actions", "delete_page" },
00175 { "notepad_actions", "rename" },
00176 } },
00177 };
00178 #endif
00179
00180 const char* menustore_get_current_menu()
00181 {
00182 return current_menu;
00183 }
00184
00185
00186 void menustore_set_current_menu(const char* name)
00187 {
00188 if (current_menu && name && strcmp(name, current_menu) == 0) return;
00189
00190 g_free(current_menu);
00191 if (name == NULL) current_menu = NULL;
00192 else current_menu = g_strdup(name);
00193 g_popup_has_changed = TRUE;
00194 g_toolbar_has_changed = TRUE;
00195 }
00196
00197
00198 static void add_system_groups()
00199 {
00200 LOGPRINTF("entry");
00201
00202 menustore_add_group("system_top", NULL, NULL, NULL);
00203 menustore_add_item( "desktop", "system_top", _("Go to Home"), "desktop");
00204 menustore_add_item( "back_to_library", "system_top", "", "back_to_library");
00205 menustore_set_item_state("back_to_library", "system_top", "disabled");
00206
00207 menustore_add_group("system_bottom", NULL, NULL, NULL);
00208 menustore_add_item( "rotate_screen", "system_bottom", _("Rotate"), "rotate_screen");
00209 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00210 menustore_add_item( "lock", "system_bottom", _("Lock Sensors"), "lock");
00211 menustore_add_item( "eject_card", "system_bottom", _("Safely Remove"), "eject_card");
00212 menustore_add_item( "shutdown", "system_bottom", _("Turn Off Device"),"shutdown");
00213
00214 menustore_set_item_state("eject_card", "system_bottom", "disabled");
00215 #endif
00216 }
00217
00218
00219 void menustore_set_text()
00220 {
00221 LOGPRINTF("entry");
00222
00223
00224 menustore_set_item_label("desktop", "system_top", _("Go to Home"));
00225 menustore_set_item_label("back_to_library", "system_top", "");
00226 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00227 menustore_set_item_label("lock", "system_bottom", _("Lock Sensors"));
00228 menustore_set_item_label("eject_card", "system_bottom", _("Safely Remove"));
00229 menustore_set_item_label("shutdown", "system_bottom", _("Turn Off Device"));
00230 #endif
00231 menustore_set_item_label("rotate_screen", "system_bottom", _("Rotate"));
00232 }
00233
00234
00235
00236 void menustore_create(taskbar_cb_t cb)
00237 {
00238 menu_store = gtk_tree_store_new (TREE_NUM_COLS,
00239 G_TYPE_INT,
00240 G_TYPE_STRING,
00241 G_TYPE_STRING,
00242 G_TYPE_STRING,
00243 G_TYPE_INT,
00244 GDK_TYPE_PIXBUF,
00245 GDK_TYPE_PIXBUF,
00246 G_TYPE_POINTER);
00247 taskbar_home_cb = cb;
00248 add_system_groups();
00249 menustore_set_text();
00250 }
00251
00252
00253 static char* type2str[] = {
00254 [MENU_TYPE_GROUP] = "GROUP",
00255 [MENU_TYPE_ITEM] = " ITEM",
00256 };
00257
00258
00259 static const char *state2str[] =
00260 {
00261 [MENU_STATE_NORMAL] = "normal",
00262 [MENU_STATE_SELECTED] = "selected",
00263 [MENU_STATE_DISABLED] = "disabled",
00264 [MENU_STATE_ALTERNATE] = "alternate",
00265 };
00266
00267
00268 static enum menu_state string2state(const char* statestr)
00269 {
00270 if (g_ascii_strcasecmp(statestr, "normal") == 0) return MENU_STATE_NORMAL;
00271 if (g_ascii_strcasecmp(statestr, "selected") == 0) return MENU_STATE_SELECTED;
00272 if (g_ascii_strcasecmp(statestr, "disabled") == 0) return MENU_STATE_DISABLED;
00273 if (g_ascii_strcasecmp(statestr, "alternate") == 0) return MENU_STATE_ALTERNATE;
00274 ERRORPRINTF("unknown state: %s", statestr);
00275 return -1;
00276 }
00277
00278
00279 static void pixbuf_unref(GdkPixbuf *img)
00280 {
00281 if (img != NULL) g_object_unref(img);
00282 }
00283
00284
00285 #if (TESTING_ON)
00286 static int debug_count = 0;
00287
00288 static gboolean printfunc(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, gpointer data)
00289 {
00290 enum menu_type type = MENU_TYPE_ITEM;
00291 enum menu_state state = MENU_STATE_NORMAL;
00292 gchar *name = NULL;
00293 gchar *text = NULL;
00294 gchar *icon = NULL;
00295 GdkPixbuf *img_normal = NULL;
00296 GdkPixbuf *img_alternate = NULL;
00297
00298 gtk_tree_model_get(model, iter,
00299 TREE_COL_TYPE, &type,
00300 TREE_COL_NAME, &name,
00301 TREE_COL_TEXT, &text,
00302 TREE_COL_ICON, &icon,
00303 TREE_COL_STATE, &state,
00304 TREE_COL_IMAGE_NORMAL, &img_normal,
00305 TREE_COL_IMAGE_ALTERNATE, &img_alternate,
00306 -1);
00307 int depth = gtk_tree_path_get_depth(path);
00308 char indent [20];
00309 memset(indent, ' ', sizeof(indent));
00310 indent[(depth-1)*3] = 0;
00311 gchar* pathstr = gtk_tree_path_to_string(path);
00312 printf("[%2d %s] %s%s '%s' icon=%s images=%p|%p state=%s\n", ++debug_count, type2str[type],
00313 indent, name, text, icon, img_normal, img_alternate, state2str[state]);
00314
00315 pixbuf_unref(img_normal);
00316 pixbuf_unref(img_alternate);
00317 g_free(name);
00318 g_free(text);
00319 g_free(icon);
00320 g_free(pathstr);
00321 return FALSE;
00322 }
00323 #endif
00324
00325
00326 static gboolean compare_func(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, gpointer data)
00327 {
00328 SearchArgs* args = (SearchArgs*)data;
00329 gboolean stop = FALSE;
00330
00331 gchar *name = NULL;
00332 GtkTreeIter* iter2;
00333 gtk_tree_model_get(model, iter,
00334 TREE_COL_NAME, &name,
00335 TREE_COL_ITER, &iter2,
00336 -1);
00337 if (strcmp(name, args->name) == 0) {
00338 stop = TRUE;
00339 args->found = TRUE;
00340 args->iter = iter2;
00341 }
00342
00343 g_free(name);
00344 return stop;
00345 }
00346
00347
00348 static gboolean name_exists(const char* name)
00349 {
00350 SearchArgs args;
00351 args.name = name;
00352 args.found = FALSE;
00353 args.iter = NULL;
00354 gtk_tree_model_foreach(GTK_TREE_MODEL(menu_store), compare_func, &args);
00355 return args.found;
00356 }
00357
00358
00359 static GtkTreeIter *get_iter(const char* name)
00360 {
00361 SearchArgs args;
00362 args.name = name;
00363 args.found = FALSE;
00364 args.iter = NULL;
00365 gtk_tree_model_foreach(GTK_TREE_MODEL(menu_store), compare_func, &args);
00366 if (!args.found) return NULL;
00367 return args.iter;
00368 }
00369
00370
00371 static GtkTreeIter* get_child_by_iter(const char* iname, GtkTreeIter *parent_iter)
00372 {
00373 GtkTreeIter child_iter;
00374 gboolean result = gtk_tree_model_iter_children(GTK_TREE_MODEL(menu_store), &child_iter, parent_iter);
00375 while (result == TRUE)
00376 {
00377 gboolean found = FALSE;
00378 gchar* child_name = NULL;
00379 GtkTreeIter* iter2;
00380 gtk_tree_model_get (GTK_TREE_MODEL(menu_store), &child_iter,
00381 TREE_COL_NAME, &child_name,
00382 TREE_COL_ITER, &iter2,
00383 -1);
00384 if (strcmp(iname, child_name) == 0) found = TRUE;
00385 g_free(child_name);
00386 if (found) return iter2;
00387 result = gtk_tree_model_iter_next(GTK_TREE_MODEL(menu_store), &child_iter);
00388 }
00389 return NULL;
00390 }
00391
00392
00393 static GtkTreeIter* get_child_by_name(const char* iname, const char* pname)
00394 {
00395 GtkTreeIter *parent_iter = NULL;
00396 if (pname) {
00397
00398 parent_iter = get_iter(pname);
00399 if (!parent_iter) {
00400 WARNPRINTF("parent does not exist! (iname=%s, pname=%s)", iname, pname);
00401 return 0;
00402 }
00403 }
00404
00405 return get_child_by_iter(iname, parent_iter);
00406 }
00407
00408
00409 gboolean menustore_add_group(const char *iname, const char *pname, const char *text, const char *icon)
00410 {
00411 TRACE("%s() iname=%s pname=%s text=%s\n", __func__, iname, pname, text);
00412
00413
00414 if (name_exists(iname)) {
00415 LOGPRINTF("name '%s' already used, re-adding", iname);
00416 menustore_remove_group(iname);
00417 }
00418
00419
00420 GtkTreeIter *parent_iter = NULL;
00421 if (pname != NULL && strlen(pname) > 0) {
00422 parent_iter = get_iter(pname);
00423 if (!parent_iter) {
00424 WARNPRINTF("parent does not exist! (iname=%s, pname=%s)", iname, pname);
00425 return FALSE;
00426 }
00427 }
00428
00429
00430 GtkTreeIter iter;
00431 gtk_tree_store_append (GTK_TREE_STORE(menu_store), &iter, parent_iter);
00432 gtk_tree_store_set (GTK_TREE_STORE(menu_store), &iter,
00433 TREE_COL_TYPE, MENU_TYPE_GROUP,
00434 TREE_COL_NAME, iname,
00435 TREE_COL_TEXT, text,
00436 TREE_COL_ICON, icon,
00437 TREE_COL_STATE, MENU_STATE_NORMAL,
00438 TREE_COL_IMAGE_NORMAL, pixlist_icon_state(icon, "normal"),
00439 TREE_COL_ITER, gtk_tree_iter_copy(&iter),
00440 -1);
00441 g_popup_has_changed = TRUE;
00442 g_toolbar_has_changed = TRUE;
00443 return TRUE;
00444 }
00445
00446
00447 gboolean menustore_add_item(const char *iname, const char *pname, const char *text, const char *icon)
00448 {
00449 TRACE("%s() iname=%s pname=%s text=%s\n", __func__, iname, pname, text);
00450
00451
00452 if (pname == 0 || strlen(pname) == 0) {
00453 WARNPRINTF("no pname (iname=%s)", iname);
00454 return FALSE;
00455 }
00456
00457
00458 GtkTreeIter *parent_iter = get_iter(pname);
00459 if (!parent_iter) {
00460 WARNPRINTF("parent does not exist! (iname=%s, pname=%s)", iname, pname);
00461 return FALSE;
00462 }
00463
00464
00465 if (get_child_by_iter(iname, parent_iter)) {
00466 ERRORPRINTF("name '%s.%s' already used", pname, iname);
00467 return FALSE;
00468 }
00469
00470
00471 GtkTreeIter iter;
00472 gtk_tree_store_append (GTK_TREE_STORE(menu_store), &iter, parent_iter);
00473 gtk_tree_store_set (GTK_TREE_STORE(menu_store), &iter,
00474 TREE_COL_TYPE, MENU_TYPE_ITEM,
00475 TREE_COL_NAME, iname,
00476 TREE_COL_TEXT, text,
00477 TREE_COL_ICON, icon,
00478 TREE_COL_STATE, MENU_STATE_NORMAL,
00479 TREE_COL_IMAGE_NORMAL, pixlist_icon_state(icon, "normal"),
00480 TREE_COL_IMAGE_ALTERNATE, pixlist_icon_state(icon, "alternate"),
00481 TREE_COL_ITER, gtk_tree_iter_copy(&iter),
00482 -1);
00483 g_popup_has_changed = TRUE;
00484 g_toolbar_has_changed = TRUE;
00485 return TRUE;
00486 }
00487
00488
00489 static gboolean check_group(const char* group, const char* iname)
00490 {
00491 if (strlen(group) > 0 && !name_exists(group))
00492 {
00493 WARNPRINTF("cannot find group '%s' for item %s", group, iname);
00494 return FALSE;
00495 }
00496 return TRUE;
00497 }
00498
00499
00500 static void add_menu_group2(GList** list, const char* group)
00501 {
00502 if (strlen(group) != 0) {
00503 *list = g_list_prepend(*list, g_strdup(group));
00504 }
00505 }
00506
00507
00508 static MenuEntry* find_menu(const char* name)
00509 {
00510 if (name == NULL) return NULL;
00511
00512 GList *iter = g_list_first(menu_list);
00513 while (iter != NULL)
00514 {
00515 MenuEntry *entry = (MenuEntry *) iter->data;
00516 if (strcmp(entry->name, name) == 0) return entry;
00517 iter = g_list_next(iter);
00518 }
00519 return NULL;
00520 }
00521
00522
00523 const char* menustore_get_current_service()
00524 {
00525 MenuEntry *entry = find_menu(current_menu);
00526 if (entry) return entry->service;
00527 return "";
00528 }
00529
00530
00531 gboolean menustore_add_menu(const char *iname, const char *ilabel, const char *service,
00532 const char *group1, const char *group2,
00533 const char *group3, const char *group4)
00534 {
00535 TRACE("%s() iname=%s ilabel=%s service=%s groups={%s, %s, %s, %s)\n", __func__,
00536 iname, ilabel, service, group1, group2, group3, group4);
00537
00538
00539 if (find_menu(iname)) {
00540 LOGPRINTF("name '%s' already used, re-adding", iname);
00541 menustore_remove_menu(iname);
00542 }
00543
00544
00545 if (!check_group(group1, iname)) return FALSE;
00546 if (!check_group(group2, iname)) return FALSE;
00547 if (!check_group(group3, iname)) return FALSE;
00548 if (!check_group(group4, iname)) return FALSE;
00549
00550
00551 MenuEntry *new_menu = g_new0 (MenuEntry, 1);
00552 new_menu->name = g_strdup(iname);
00553 new_menu->service = g_strdup(service);
00554 new_menu->groups = NULL;
00555 menu_list = g_list_append(menu_list, new_menu);
00556
00557
00558 add_menu_group2(&new_menu->groups, group1);
00559 add_menu_group2(&new_menu->groups, group2);
00560 add_menu_group2(&new_menu->groups, group3);
00561 add_menu_group2(&new_menu->groups, group4);
00562
00563 g_popup_has_changed = TRUE;
00564 g_toolbar_has_changed = TRUE;
00565 return TRUE;
00566 }
00567
00568
00569 static gboolean check_type(GtkTreeIter* iter, const char* name, enum menu_type type)
00570 {
00571 enum menu_type realtype = MENU_TYPE_ITEM;
00572 gtk_tree_model_get (GTK_TREE_MODEL(menu_store), iter,
00573 TREE_COL_TYPE, &realtype,
00574 -1);
00575 if (realtype != type)
00576 {
00577 WARNPRINTF("'%s' is not of type %s", name, type2str[type]);
00578 return FALSE;
00579 }
00580 return TRUE;
00581 }
00582
00583
00584 gboolean menustore_remove_group(const char *name)
00585 {
00586 TRACE("%s() name=%s\n", __func__, name);
00587
00588
00589 GtkTreeIter *menu_iter = get_iter(name);
00590 if (menu_iter == NULL)
00591 {
00592 LOGPRINTF("'%s' not found", name);
00593 return FALSE;
00594 }
00595
00596 if (!check_type(menu_iter, name, MENU_TYPE_GROUP)) return FALSE;
00597
00598
00599 GtkTreeIter child_iter;
00600 if (gtk_tree_model_iter_children(GTK_TREE_MODEL(menu_store), &child_iter, menu_iter))
00601 {
00602 enum menu_type type = MENU_TYPE_ITEM;
00603 gchar* child_name = NULL;
00604 gtk_tree_model_get (GTK_TREE_MODEL(menu_store), &child_iter,
00605 TREE_COL_NAME, &child_name,
00606 TREE_COL_TYPE, &type,
00607 -1);
00608 switch (type) {
00609 case MENU_TYPE_GROUP:
00610 menustore_remove_group(child_name);
00611 break;
00612 case MENU_TYPE_ITEM:
00613 menustore_remove_item(child_name, name);
00614 break;
00615 }
00616 g_free(child_name);
00617 }
00618
00619
00620 gtk_tree_store_remove(GTK_TREE_STORE(menu_store), menu_iter);
00621 gtk_tree_iter_free(menu_iter);
00622
00623 g_popup_has_changed = TRUE;
00624 g_toolbar_has_changed = TRUE;
00625 return TRUE;
00626 }
00627
00628
00629 gboolean menustore_remove_item(const char *iname, const char* pname)
00630 {
00631 TRACE("%s() iname=%s pname=%s\n", __func__, iname, pname);
00632
00633
00634 if (pname == 0 || strlen(pname) == 0) {
00635 WARNPRINTF("no pname (iname=%s)", iname);
00636 return FALSE;
00637 }
00638
00639
00640 GtkTreeIter *parent_iter = get_iter(pname);
00641 if (!parent_iter) {
00642 WARNPRINTF("parent does not exist! (iname=%s, pname=%s)", iname, pname);
00643 return FALSE;
00644 }
00645
00646
00647 GtkTreeIter *child_iter = get_child_by_iter(iname, parent_iter);
00648 if (!child_iter) {
00649 LOGPRINTF("'%s.%s' not found", pname, iname);
00650 return FALSE;
00651 }
00652
00653 if (!check_type(child_iter, iname, MENU_TYPE_ITEM)) return FALSE;
00654
00655
00656 gtk_tree_store_remove(GTK_TREE_STORE(menu_store), child_iter);
00657 gtk_tree_iter_free(child_iter);
00658
00659 g_popup_has_changed = TRUE;
00660 g_toolbar_has_changed = TRUE;
00661 return TRUE;
00662 }
00663
00664
00665 static void free_menu_entry(MenuEntry* entry)
00666 {
00667 g_free(entry->name);
00668 g_free(entry->service);
00669 g_free(entry);
00670 }
00671
00672
00673 gboolean menustore_remove_menu(const char *name)
00674 {
00675 TRACE("%s() name=%s\n", __func__, name);
00676
00677 GList *iter = g_list_first(menu_list);
00678 while (iter != NULL)
00679 {
00680 MenuEntry *entry = (MenuEntry *) iter->data;
00681 if (strcmp(entry->name, name) == 0) break;
00682 iter = g_list_next(iter);
00683 }
00684
00685 if (iter == NULL) {
00686 WARNPRINTF("menu '%s' not found", name);
00687 return FALSE;
00688 }
00689
00690 free_menu_entry(iter->data);
00691 menu_list = g_list_delete_link(menu_list, iter);
00692
00693 if (current_menu && strcmp(current_menu, name) == 0)
00694 {
00695 menustore_set_current_menu(NULL);
00696 }
00697
00698 g_popup_has_changed = TRUE;
00699 g_toolbar_has_changed = TRUE;
00700 return TRUE;
00701 }
00702
00703
00704 static GdkPixbuf *get_pixbuf(enum menu_state state, GtkTreeIter *menu_iter)
00705 {
00706 GdkPixbuf *img = NULL;
00707 switch (state)
00708 {
00709 case MENU_STATE_NORMAL:
00710 case MENU_STATE_SELECTED:
00711 case MENU_STATE_DISABLED:
00712 gtk_tree_model_get(GTK_TREE_MODEL(menu_store), menu_iter,
00713 TREE_COL_IMAGE_NORMAL, &img,
00714 -1);
00715 break;
00716
00717 case MENU_STATE_ALTERNATE:
00718 gtk_tree_model_get(GTK_TREE_MODEL(menu_store), menu_iter,
00719 TREE_COL_IMAGE_ALTERNATE, &img,
00720 -1);
00721 break;
00722 }
00723 if (img == NULL)
00724 {
00725 if (state == MENU_STATE_SELECTED)
00726 {
00727 img = pixlist_icon_state("selected", "normal");
00728 } else {
00729 img = pixlist_icon_state("blank", "normal");
00730 }
00731 if (img) g_object_ref(img);
00732 }
00733 return img;
00734 }
00735
00736
00737 static gboolean update_state(GtkTreeIter* iter, const char* iname, const char* pname, const char* stateStr)
00738 {
00739 enum menu_state state = string2state(stateStr);
00740 if ((gint) state == -1) return FALSE;
00741
00742
00743 gtk_tree_store_set(GTK_TREE_STORE(menu_store), iter,
00744 TREE_COL_STATE, state,
00745 -1);
00746
00747 g_popup_has_changed = TRUE;
00748 g_toolbar_has_changed = TRUE;
00749 return TRUE;
00750 }
00751
00752
00753 gboolean menustore_set_group_state(const char *name, const char *stateStr)
00754 {
00755 TRACE("%s() name=%s state=%s\n", __func__, name, stateStr);
00756
00757 GtkTreeIter *iter = get_iter(name);
00758 if (iter == NULL)
00759 {
00760 LOGPRINTF("'%s' not found", name);
00761 return FALSE;
00762 }
00763
00764 if (!check_type(iter, name, MENU_TYPE_GROUP)) return FALSE;
00765
00766 return update_state(iter, name, NULL, stateStr);
00767 }
00768
00769
00770 gboolean menustore_set_item_state(const char *iname, const char *pname, const char *stateStr)
00771 {
00772 TRACE("%s() iname=%s pname=%s state=%s\n", __func__, iname, pname, stateStr);
00773
00774 if ( (pname != NULL) && strcmp(pname, "general")==0 )
00775 {
00776 pname = "system_bottom";
00777 }
00778
00779
00780 GtkTreeIter *iter = get_child_by_name(iname, pname);
00781 if (iter == NULL)
00782 {
00783 LOGPRINTF("'%s.%s' not found", pname, iname);
00784 return FALSE;
00785 }
00786
00787 return update_state(iter, iname, pname, stateStr);
00788 }
00789
00790
00791 static void update_label(GtkTreeIter* iter, const char* iname, const char* pname, const char* label)
00792 {
00793
00794 gtk_tree_store_set(GTK_TREE_STORE(menu_store), iter,
00795 TREE_COL_TEXT, label,
00796 -1);
00797 g_popup_has_changed = TRUE;
00798 }
00799
00800
00801 gboolean menustore_set_group_label(const char *name, const char *label)
00802 {
00803 TRACE("%s() name=%s label=%s\n", __func__, name, label);
00804
00805
00806 GtkTreeIter *iter = get_iter(name);
00807 if (iter == NULL)
00808 {
00809 LOGPRINTF("'%s' not found", name);
00810 return FALSE;
00811 }
00812
00813
00814 if (!check_type(iter, name, MENU_TYPE_GROUP)) return FALSE;
00815
00816 update_label(iter, name, NULL, label);
00817 return TRUE;
00818 }
00819
00820
00821 gboolean menustore_set_item_label(const char *iname, const char *pname, const char *label)
00822 {
00823 TRACE("%s() iname=%s pname=%s label=%s\n", __func__, iname, pname, label);
00824
00825
00826 GtkTreeIter *iter = get_child_by_name(iname, pname);
00827 if (iter == NULL)
00828 {
00829 LOGPRINTF("'%s.%s' not found", pname, iname);
00830 return FALSE;
00831 }
00832
00833 update_label(iter, iname, pname, label);
00834 return TRUE;
00835 }
00836
00837
00838 gboolean menustore_popup_has_changed()
00839 {
00840 return g_popup_has_changed;
00841 }
00842
00843
00844 void menustore_clear_popup_changed()
00845 {
00846 g_popup_has_changed = FALSE;
00847 }
00848
00849
00850 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00851 gboolean menustore_toolbar_has_changed()
00852 {
00853 return g_toolbar_has_changed;
00854 }
00855
00856
00857 void menustore_clear_toolbar_changed()
00858 {
00859 g_toolbar_has_changed = FALSE;
00860 }
00861
00862
00863 static MenuToolItems* find_tools_for_menu(const char* menu)
00864 {
00865 if (menu == NULL) return NULL;
00866
00867 int num = sizeof(hardcoded_tools) / sizeof(hardcoded_tools[0]);
00868 int i;
00869 for (i=0; i<num; i++) {
00870 const char* hardcoded = hardcoded_tools[i].menu;
00871
00872 if (strncmp(hardcoded, menu, strlen(hardcoded)) == 0) {
00873 return &hardcoded_tools[i];
00874 }
00875 }
00876 return NULL;
00877 }
00878
00879
00880 int menustore_get_tool_limit()
00881 {
00882
00883 MenuToolItems* tools = find_tools_for_menu(current_menu);
00884 if (tools == NULL) return 0;
00885
00886 ToolItem* item = &tools->items[MENUSTORE_SMALL_TOOLS];
00887 if (item->pname == NULL) return MENUSTORE_SMALL_TOOLS;
00888 return MENUSTORE_NUM_TOOLS;
00889 }
00890
00891
00892 GdkPixbuf* menustore_get_tool_icon(int index)
00893 {
00894 g_assert(index < MENUSTORE_NUM_TOOLS);
00895
00896 MenuToolItems* tools = find_tools_for_menu(current_menu);
00897 if (tools == NULL) goto blank;
00898
00899 ToolItem* item = &tools->items[index];
00900 if (item->pname == NULL || item->iname == NULL) goto blank;
00901 GtkTreeIter *iter = get_child_by_name(item->iname, item->pname);
00902 if (iter == NULL) {
00903 ERRORPRINTF("'%s.%s' not found", item->pname, item->iname);
00904 goto blank;
00905 }
00906
00907 enum menu_state state;
00908 gchar *icon_name = NULL;
00909 gtk_tree_model_get(GTK_TREE_MODEL(menu_store), iter,
00910 TREE_COL_STATE, &state,
00911 TREE_COL_ICON, &icon_name,
00912 -1);
00913 GdkPixbuf* img = pixlist_toolbar_icon(icon_name, state2str[state]);
00914 g_free(icon_name);
00915 return img;
00916 blank:
00917 return pixlist_icon_state("toolbar_blank", "normal");
00918 }
00919
00920
00921 void menustore_activate_toolitem(int index, tool_func_t func)
00922 {
00923 g_assert(index < MENUSTORE_NUM_TOOLS);
00924
00925
00926 MenuToolItems* tools = find_tools_for_menu(current_menu);
00927 if (tools == NULL) {
00928 WARNPRINTF("no tool for menu");
00929 return;
00930 }
00931
00932
00933 ToolItem* item = &tools->items[index];
00934 if (item->pname == NULL || item->iname == NULL) return;
00935
00936 menustore_activate_item(item->pname, item->iname, func);
00937 }
00938 #endif
00939
00940
00941 gboolean menustore_activate_item_iter(gpointer user_data, tool_func_t func)
00942 {
00943 GtkTreeIter* iter = (GtkTreeIter*) user_data;
00944
00945 gchar *iname;
00946 enum menu_type type = MENU_TYPE_ITEM;
00947 enum menu_state state = MENU_STATE_NORMAL;
00948 gtk_tree_model_get(GTK_TREE_MODEL (menu_store), iter,
00949 TREE_COL_TYPE, &type,
00950 TREE_COL_NAME, &iname,
00951 TREE_COL_STATE, &state,
00952 -1);
00953
00954 if (type != MENU_TYPE_ITEM) {
00955 goto error;
00956 }
00957 if (state == MENU_STATE_DISABLED)
00958 {
00959 WARNPRINTF("cannot activate disabled item");
00960 goto error;
00961 }
00962
00963 GtkTreeIter parent_iter;
00964 gtk_tree_model_iter_parent(GTK_TREE_MODEL (menu_store),
00965 &parent_iter,
00966 iter);
00967 gchar *pname;
00968 gtk_tree_model_get(GTK_TREE_MODEL (menu_store), &parent_iter,
00969 TREE_COL_NAME, &pname,
00970 -1);
00971
00972 if ((strcmp(pname, "system_top") == 0) || (strcmp(pname, "system_bottom") == 0))
00973 {
00974 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00975
00976 if ( (strcmp(iname, "desktop") == 0) || (strcmp(iname, "back_to_library") == 0) )
00977 {
00978 taskbar_home_cb();
00979 }
00980 #endif
00981 if (strcmp(iname, "back_to_library") == 0)
00982 {
00983 func(iname, "tasks", current_menu, state2str[state], DBUS_SERVICE_SYSTEM_CONTROL);
00984 }
00985 else
00986 {
00987 func(iname, "general", current_menu, state2str[state], DBUS_SERVICE_SYSTEM_CONTROL);
00988 }
00989 }
00990 else
00991 {
00992 func(iname, pname, current_menu, state2str[state], menustore_get_current_service());
00993 }
00994 g_free(iname);
00995 g_free(pname);
00996 return TRUE;
00997 error:
00998 g_free(iname);
00999 return FALSE;
01000 }
01001
01002
01003 void menustore_activate_item(const char* pname, const char* iname, tool_func_t func)
01004 {
01005 LOGPRINTF("entry [%s.%s]", pname, iname);
01006
01007 GtkTreeIter *iter = get_child_by_name(iname, pname);
01008 if (iter == NULL) {
01009 ERRORPRINTF("'%s.%s' not found", pname, iname);
01010 return;
01011 }
01012 menustore_activate_item_iter(iter, func);
01013 }
01014
01015
01016 static gboolean fill_add_group(const char* group,
01017 add_item_func item_cb,
01018 add_item_func submenu_cb,
01019 separator_func separator_cb,
01020 gpointer user_data)
01021 {
01022 GtkTreeIter *menu_iter = get_iter(group);
01023 if (menu_iter == NULL)
01024 {
01025 WARNPRINTF("entry: name [%s] not found", group);
01026 return FALSE;
01027 }
01028
01029
01030 gint num_items = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(menu_store), menu_iter);
01031 if (num_items == 0)
01032 {
01033 WARNPRINTF("given group `%s` has no children", group);
01034 return FALSE;
01035 }
01036
01037 gboolean rc = FALSE;
01038
01039 GtkTreeIter child_iter;
01040 gboolean result = gtk_tree_model_iter_children(GTK_TREE_MODEL(menu_store), &child_iter, menu_iter);
01041 while (result == TRUE)
01042 {
01043
01044 gchar *name = NULL;
01045 gchar *text = NULL;
01046 enum menu_type type = MENU_TYPE_ITEM;
01047 enum menu_state state = MENU_STATE_NORMAL;
01048 gtk_tree_model_get(GTK_TREE_MODEL(menu_store), &child_iter,
01049 TREE_COL_NAME, &name,
01050 TREE_COL_TEXT, &text,
01051 TREE_COL_STATE, &state,
01052 TREE_COL_TYPE, &type,
01053 -1);
01054
01055 if (state != MENU_STATE_DISABLED && strcmp("", text) == 0) {
01056 LOGPRINTF("empty label for %s.%s", group, name);
01057 }
01058
01059 GdkPixbuf *img = get_pixbuf(state, &child_iter);
01060 GtkTreeIter *iter_copy = gtk_tree_iter_copy(&child_iter);
01061
01062 int count = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(menu_store), &child_iter);
01063 if (type == MENU_TYPE_GROUP && count != 0) {
01064 gpointer user_data2 = submenu_cb(name, text, state, img, iter_copy, user_data);
01065 separator_cb(user_data2);
01066 GtkTreeIter child_child;
01067 gboolean is_next = gtk_tree_model_iter_children(GTK_TREE_MODEL(menu_store), &child_child, &child_iter);
01068 while (is_next)
01069 {
01070 gchar *group_name = NULL;
01071 gtk_tree_model_get(GTK_TREE_MODEL(menu_store), &child_child,
01072 TREE_COL_NAME, &group_name,
01073 -1);
01074
01075
01076 gboolean is_added = fill_add_group(group_name, item_cb, submenu_cb, separator_cb, user_data2);
01077 g_free(group_name);
01078
01079 is_next = gtk_tree_model_iter_next(GTK_TREE_MODEL(menu_store), &child_child);
01080 if (is_added && is_next)
01081 {
01082
01083 separator_cb(user_data2);
01084 }
01085 }
01086 } else {
01087 item_cb(name, text, state, img, iter_copy, user_data);
01088 }
01089
01090 pixbuf_unref(img);
01091 g_free(name);
01092 g_free(text);
01093
01094 if (state != MENU_STATE_DISABLED) rc = TRUE;
01095
01096 result = gtk_tree_model_iter_next(GTK_TREE_MODEL(menu_store), &child_iter);
01097 }
01098 return rc;
01099 }
01100
01101
01102 static const GList* get_menu_groups()
01103 {
01104 MenuEntry *entry = find_menu(current_menu);
01105 if (entry) return entry->groups;
01106 return NULL;
01107 }
01108
01109
01110 void menustore_fill_menu(add_item_func item_cb,
01111 add_item_func submenu_cb,
01112 separator_func separator_cb,
01113 gpointer user_data)
01114 {
01115 fill_add_group("system_top", item_cb, submenu_cb, separator_cb, user_data);
01116 separator_cb(user_data);
01117
01118 gboolean is_added = FALSE;
01119 const GList *groups = get_menu_groups();
01120 while (groups) {
01121 is_added = fill_add_group((const char*)groups->data, item_cb, submenu_cb, separator_cb, user_data);
01122
01123 if (is_added) separator_cb(user_data);
01124
01125 groups = g_list_next(groups);
01126 }
01127
01128 fill_add_group("system_bottom", item_cb, submenu_cb, separator_cb, user_data);
01129 }
01130
01131
01132 #if (TESTING_ON)
01133 static void testing_extra_prints()
01134 {
01135 printf("Current menu = '%s' service='%s'\n",
01136 current_menu, menustore_get_current_service());
01137 printf("---- %s() MENULIST:\n", __func__);
01138 GList *iter = g_list_first(menu_list);
01139 while (iter != NULL)
01140 {
01141 MenuEntry *entry = (MenuEntry *) iter->data;
01142 printf("%s service=%s\n", entry->name, entry->service);
01143 GList *iter2 = g_list_first(entry->groups);
01144 while (iter2) {
01145 printf(" %s\n", (const char*)iter2->data);
01146 iter2 = g_list_next(iter2);
01147 }
01148 iter = g_list_next(iter);
01149 }
01150
01151 printf("\n---- %s() MENU_STORE:\n", __func__);
01152 debug_count = 0;
01153 gtk_tree_model_foreach(GTK_TREE_MODEL(menu_store), printfunc, NULL);
01154
01155 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
01156 printf("\n---- %s() HARDCODED TOOLITEMS:\n", __func__);
01157 int num = sizeof(hardcoded_tools) / sizeof(hardcoded_tools[0]);
01158 int i;
01159 for (i=0; i<num; i++) {
01160 MenuToolItems* tools = &hardcoded_tools[i];
01161
01162 printf(" %s\n", tools->menu);
01163 int i;
01164 for (i=0; i<MENUSTORE_NUM_TOOLS; i++) {
01165 if (tools->items[i].pname) {
01166 printf(" [%2d] %s.%s\n", i, tools->items[i].pname, tools->items[i].iname);
01167 }
01168 }
01169 }
01170 #endif
01171 }
01172
01173 static char buffer[1000];
01174 static char* cp = NULL;
01175
01176 gpointer print_item(const char* name,
01177 const char* text,
01178 enum menu_state state,
01179 GdkPixbuf* img,
01180 gpointer menu_data,
01181 gpointer user_data)
01182 {
01183 strcpy(cp, name);
01184 cp += strlen(name);
01185 *cp++ = '\n';
01186 return NULL;
01187 }
01188
01189
01190 void print_separator(gpointer user_data) {}
01191
01192
01193 static gboolean find_route(const char* pname, const char* iname, const char* group, char** route, gboolean top_lvl)
01194 {
01195 char* orig = *route;
01196 char *rp = *route;
01197 GtkTreeIter *group_iter = get_iter(group);
01198 g_assert(group_iter);
01199
01200 GtkTreeIter child_iter;
01201 gboolean result = gtk_tree_model_iter_children(GTK_TREE_MODEL(menu_store), &child_iter, group_iter);
01202 gboolean found = FALSE;
01203 while (result == TRUE)
01204 {
01205
01206 gchar *name = NULL;
01207 gchar *text = NULL;
01208 enum menu_type type = MENU_TYPE_ITEM;
01209 enum menu_state state = MENU_STATE_NORMAL;
01210 gtk_tree_model_get(GTK_TREE_MODEL(menu_store), &child_iter,
01211 TREE_COL_NAME, &name,
01212 TREE_COL_TEXT, &text,
01213 TREE_COL_STATE, &state,
01214 TREE_COL_TYPE, &type,
01215 -1);
01216 gboolean visible = TRUE;
01217 if (strcmp(name, iname) == 0 && strcmp(group, pname) == 0) found = TRUE;
01218 if (state == MENU_STATE_DISABLED || strcmp(text, "") == 0) visible = FALSE;
01219 g_free(text);
01220 if (found) {
01221 if (!visible) {
01222
01223 *orig++ = 'X';
01224 *orig = 0;
01225 } else {
01226
01227 *rp++ = 'E';
01228 *rp = 0;
01229
01230 }
01231 g_free(name);
01232 return TRUE;
01233 } else {
01234 if (visible) {
01235
01236 if (type == MENU_TYPE_GROUP) {
01237 char* before = rp;
01238 if (top_lvl) {
01239 *rp++ = 'E';
01240 *rp++ = 'D';
01241 *route = rp;
01242 }
01243
01244 gboolean found2 = find_route(pname, iname, name, route, FALSE);
01245 if (found2) {
01246 g_free(name);
01247 return TRUE;
01248 } else {
01249 if (top_lvl) {
01250 rp = before;
01251 *rp++ = 'D';
01252 *route = rp;
01253 }
01254 }
01255 } else {
01256 *rp++ = 'D';
01257 *route = rp;
01258 }
01259 } else {
01260
01261 }
01262 }
01263
01264 g_free(name);
01265 result = gtk_tree_model_iter_next(GTK_TREE_MODEL(menu_store), &child_iter);
01266 }
01267 return FALSE;
01268 }
01269
01270
01271 static const char* testing_route_to_item(const char* pname, const char* iname)
01272 {
01273 char route[128];
01274 memset(route, 0, sizeof(route));
01275 char *cp = &route[0];
01276
01277 gboolean found = find_route(pname, iname, "system_top", &cp, TRUE);
01278 if (found) goto out_found;
01279
01280 const GList *groups = get_menu_groups();
01281 while (groups) {
01282 found = find_route(pname, iname, (const char*)groups->data, &cp, TRUE);
01283 if (found) goto out_found;
01284 groups = g_list_next(groups);
01285 }
01286
01287 found = find_route(pname, iname, "system_bottom", &cp, TRUE);
01288 out_found:
01289 if (found && route[strlen(route)-1] == 'X') found = FALSE;
01290 if (!found) {
01291 route[0] = 'X';
01292 route[1] = 0;
01293 }
01294
01295 static char result[256];
01296 char *ip = &route[0];
01297 char *op = &result[0];
01298 unsigned int i = 0;
01299 for (i=0; i<strlen(route); i++) {
01300 *op++ = *ip++;
01301 *op++ = ' ';
01302 }
01303 *op = 0;
01304 return result;
01305 }
01306
01307
01308 const char* testing_menustore_print()
01309 {
01310 testing_extra_prints();
01311
01312 cp = buffer;
01313 menustore_fill_menu(print_item, print_item, print_separator, NULL);
01314 *cp = 0;
01315 return buffer;
01316 }
01317
01318
01319 const char* testing_menustore_get_route(const char* pname, const char* iname)
01320 {
01321 return testing_route_to_item(pname, iname);
01322 }
01323
01324 #endif // TESTING_ON
01325