popup.c

Go to the documentation of this file.
00001 /*
00002  * File Name: popup.c
00003  */
00004 
00005 /*
00006  * This file is part of popupmenu.
00007  *
00008  * popupmenu is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * popupmenu is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021  
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 //----------------------------------------------------------------------------
00028 // Include Files
00029 //----------------------------------------------------------------------------
00030 
00031 #include "config.h"
00032 
00033 // system include files, between < >
00034 #include <gtk/gtk.h>
00035 #include <gdk/gdkkeysyms.h>
00036 #include <string.h>
00037 
00038 // ereader include files, between < >
00039 #include <libergtk/ergtk.h>
00040 #include <liberutils/display_utils.h>
00041 
00042 // local include files, between " "
00043 #include "log.h"
00044 #include "i18n.h"
00045 #include "ipc.h"
00046 #include "menustore.h"
00047 #include "pixlist.h"
00048 #include "popup.h"
00049 
00050 //----------------------------------------------------------------------------
00051 // Global Constants
00052 //----------------------------------------------------------------------------
00053 
00054 const gint MENU_OFFSET_LEFT             = 12;
00055 const gint MENU_OFFSET_BOTTOM           = 45;
00056 
00057 
00058 //----------------------------------------------------------------------------
00059 // Static Variables
00060 //----------------------------------------------------------------------------
00061 
00062 static GtkWidget    *g_menu             = NULL;
00063 static gboolean      is_active          = FALSE;
00064 static gboolean      g_dont_show        = FALSE;
00065 
00066 
00067 //============================================================================
00068 // Local Function Definitions
00069 //============================================================================
00070 
00071 #if (TIMING_ON)
00072 #include <stdlib.h>
00073 #include <time.h>
00074 static u_int64_t get_time_now()
00075 {
00076     struct timespec now;
00077     clock_gettime(CLOCK_MONOTONIC, &now);
00078     u_int64_t now64 = now.tv_sec;
00079     now64 *= 1000000;
00080     now64 += (now.tv_nsec/1000);
00081     return now64;
00082 }
00083 
00084 static u_int64_t t1 = 0;
00085 static u_int64_t t2 = 0;
00086 
00087 static void start_timer()
00088 {
00089     LOGPRINTF("");
00090     if (t1 == 0) t1 = get_time_now();
00091 }
00092 
00093 
00094 static void stop_timer(const char* text)
00095 {
00096     if (t1 != 0) {
00097         t2 = get_time_now();
00098         float duration = t2 - t1;
00099         printf("%s DURATION = %4.1lf ms\n\n", text, duration / 1000);
00100         t1 = 0;
00101     }
00102 }
00103 #endif
00104 
00105 static void set_active          (gboolean do_active);
00106 static void idle_update_display (gint type);
00107 
00108 
00109 //============================================================================
00110 // Functions Implementation
00111 //============================================================================
00112 
00113 
00114 gboolean popup_set_popup_show(const char* statestr)
00115 {
00116     gboolean last_active = is_active;
00117 
00118     if (g_dont_show)
00119     {
00120         return FALSE;
00121     }
00122     
00123     if (g_ascii_strcasecmp(statestr, "show") == 0)
00124     {
00125         set_active(TRUE);
00126     }
00127     else if (g_ascii_strcasecmp(statestr, "hide") == 0)
00128     {
00129         set_active(FALSE);
00130     }
00131     else if (g_ascii_strcasecmp(statestr, "toggle") == 0)
00132     {
00133         set_active(!is_active);
00134     }
00135     else if (g_ascii_strcasecmp(statestr, "block") == 0)
00136     {
00137         // close and block popup
00138         set_active(FALSE);
00139         ipc_set_enabled(FALSE);
00140     }
00141     else if (g_ascii_strcasecmp(statestr, "unblock") == 0)
00142     {
00143         set_active(FALSE);
00144         ipc_set_enabled(TRUE);
00145     }
00146     else
00147     {
00148         ERRORPRINTF("state unknown: %s", statestr);
00149     }
00150 
00151     return (last_active != is_active);
00152 }
00153 
00154 
00155 void popup_set_popup_block(gboolean block)
00156 {
00157     g_dont_show = block;
00158 }
00159 
00160 
00161 gboolean popup_get_popup_block()
00162 {
00163     return g_dont_show;
00164 }
00165 
00166 
00167 static void set_menuitem_markup(GtkWidget* widget, const char* text, int state)
00168 {
00169     LOGPRINTF("text='%s'  state=%d", text, state);
00170     GtkWidget *itemlabel = gtk_bin_get_child(GTK_BIN(widget));
00171 
00172     // update text
00173     gchar *markup = NULL;
00174     if (state == MENU_STATE_SELECTED) {
00175         markup = g_markup_printf_escaped("<span weight=\"bold\">%s</span>", text);
00176     }
00177     else
00178     {
00179         markup = g_markup_escape_text(text, -1);
00180     }
00181     gtk_label_set_markup(GTK_LABEL(itemlabel), markup);
00182     g_free(markup);
00183 
00184     // update visibility
00185     if (state == MENU_STATE_DISABLED || text[0] == 0)
00186     {
00187 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00188         if (text[0] != 0) {
00189             gtk_widget_set_sensitive(widget, FALSE);
00190             gtk_widget_show(widget);
00191         } else {
00192             gtk_widget_hide(widget);
00193 
00194         }
00195 #else
00196         gtk_widget_hide(widget);
00197 #endif
00198     }
00199     else
00200     {
00201         gtk_widget_show(widget);
00202     }
00203 }
00204 
00205 
00206 //============================================================================
00207 // Local Functions Implementation
00208 //============================================================================
00209 
00210 static void on_menu_deactivate(GtkMenuShell *menu, gpointer user_data)
00211 {
00212     set_active(FALSE);
00213 }
00214 
00215 
00216 static gboolean on_menu_key_press(GtkMenuShell *menu, GdkEventKey *event, gpointer user_data)
00217 {
00218     LOGPRINTF("entry: type [%d] keyval [%d]", event->type, event->keyval);
00219     
00220     if (event && (event->type == GDK_KEY_PRESS))
00221     {
00222         switch (event->keyval)
00223         {
00224         case GDK_F1:
00225             set_active(FALSE);
00226             break;
00227         case GDK_F10:
00228             ipc_sys_standby();
00229             break;
00230         default:
00231             break;
00232         }
00233     }
00234     return FALSE;
00235 }
00236 
00237 
00238 static void on_item_back_activate(GtkMenuItem *item, gpointer user_data)
00239 {
00240     GtkWidget *menu_shell = GTK_WIDGET(user_data);
00241 
00242     // close submenu and go back to parent
00243     g_signal_emit_by_name(menu_shell, "move-current", GTK_MENU_DIR_PARENT, NULL);
00244 }
00245 
00246 
00247 static void on_item_activate(GtkMenuItem *item, gpointer menu_data)
00248 {
00249     gboolean ok = menustore_activate_item_iter(menu_data, ipc_send_item_activated);
00250     if (ok) set_active(FALSE);
00251 }
00252 
00253 
00254 static void on_menu_move_scroll(GtkMenu      *menu,
00255                                 GtkScrollType arg1,
00256                                 gpointer      user_data)  
00257 {
00258     display_gain_control();
00259     idle_update_display(DM_HINT_CURSOR);
00260 }
00261 
00262 
00263 static gboolean on_menu_move_selected(GtkMenuShell *menu_shell,
00264                                       gint          distance,
00265                                       gpointer      user_data)
00266 {
00267     display_gain_control();
00268     idle_update_display(DM_HINT_CURSOR);
00269     return FALSE;
00270 }
00271 
00272 
00273 static void menu_set_position(GtkMenu *menu,
00274                               gint *x,
00275                               gint *y,
00276                               gboolean *push_in,
00277                               gpointer user_data)
00278 {
00279     g_assert(g_menu);
00280     if (menu == GTK_MENU(g_menu))
00281     {
00282         gint w, h;
00283         GtkRequisition req;
00284 
00285         gdk_window_get_geometry(gdk_get_default_root_window(), NULL, NULL, &w, &h, NULL);
00286         gtk_widget_size_request(g_menu, &req);
00287         
00288         *x = MENU_OFFSET_LEFT; 
00289         *y = h - MENU_OFFSET_BOTTOM - req.height; 
00290         //LOGPRINTF("screen w [%d] h [%d], requested w [%d] h [%d], x [%d] y [%d]", w, h, req.width, req.height, *x, *y);
00291     }
00292 }
00293 
00294 
00295 static GtkWidget *create_item(const gchar *text, GdkPixbuf *img)
00296 {
00297     GtkWidget *widget = gtk_image_menu_item_new_with_label(text);
00298     GtkWidget *item_image = gtk_image_new_from_pixbuf(img);
00299     gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget),item_image);
00300     gtk_widget_show(item_image);
00301     gtk_widget_show(widget);
00302     
00303     return widget;
00304 }
00305 
00306 
00307 static gpointer add_popup_item(const char* name,
00308                            const char* text,
00309                            enum menu_state state,
00310                            GdkPixbuf *img,
00311                            gpointer menu_data,
00312                            gpointer user_data)
00313 {
00314     GtkWidget *widget = create_item(text, img);
00315     set_menuitem_markup(widget, text, state);
00316 
00317     // add item to menu
00318     gtk_menu_shell_append(GTK_MENU_SHELL(user_data), widget);
00319 
00320     g_signal_connect(G_OBJECT(widget), "activate", G_CALLBACK(on_item_activate), menu_data);
00321     return widget;
00322 }
00323 
00324 
00325 static gpointer add_popup_submenu(const char* name,
00326                                   const char* text,
00327                                   enum menu_state state,
00328                                   GdkPixbuf *img,
00329                                   gpointer menu_data,
00330                                   gpointer user_data)
00331 {
00332     GtkWidget* widget = add_popup_item(name, text, state, img, menu_data, user_data);
00333 
00334     // add submenu to item
00335     GtkWidget *submenu = gtk_menu_new();
00336     gtk_signal_connect(GTK_OBJECT(submenu), "key-press-event", GTK_SIGNAL_FUNC(on_menu_key_press), NULL);
00337     g_signal_connect(G_OBJECT(submenu), "move-scroll", G_CALLBACK(on_menu_move_scroll), NULL);
00338     g_signal_connect(G_OBJECT(submenu), "move-selected", G_CALLBACK(on_menu_move_selected), NULL);
00339     g_signal_connect(G_OBJECT(submenu), "deactivate", G_CALLBACK(on_menu_deactivate), NULL);
00340     gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), submenu);
00341     gtk_widget_show_all(submenu);
00342 
00343     // add Back button
00344     GtkWidget *back_item = create_item(_("Back"), pixlist_icon_state("back", "normal"));
00345     g_signal_connect(G_OBJECT(back_item), "activate", G_CALLBACK(on_item_back_activate), submenu);
00346     gtk_menu_item_set_keep_active(GTK_MENU_ITEM(back_item), TRUE);
00347     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), back_item);
00348 
00349     return submenu;
00350 }
00351 
00352 
00353 static void add_popup_separator(gpointer user_data)
00354 {
00355     GtkWidget* menu = (GtkWidget*)user_data;
00356     GtkWidget *widget = gtk_separator_menu_item_new();
00357     gtk_menu_shell_append(GTK_MENU_SHELL(menu), widget);
00358     gtk_widget_show(widget);
00359 }
00360 
00361 
00362 static void create_menu()
00363 {
00364     if (g_menu && !menustore_popup_has_changed()) {
00365         // use cached menu
00366         return;
00367     }    
00368     menustore_clear_popup_changed();
00369 
00370     if (g_menu)
00371     {
00372         // remove existing menu
00373         gtk_widget_destroy(g_menu);
00374         g_menu = NULL;
00375     }
00376 
00377     // create main menu
00378     GtkWidget *widget = gtk_menu_new();
00379     gtk_signal_connect(GTK_OBJECT(widget), "key-press-event", GTK_SIGNAL_FUNC(on_menu_key_press), NULL);
00380     g_signal_connect(G_OBJECT(widget), "deactivate", G_CALLBACK(on_menu_deactivate), NULL);
00381     g_signal_connect(G_OBJECT(widget), "move-scroll", G_CALLBACK(on_menu_move_scroll), NULL);
00382     g_signal_connect(G_OBJECT(widget), "move-selected", G_CALLBACK(on_menu_move_selected), NULL);
00383     g_menu = widget;
00384     
00385     menustore_fill_menu(add_popup_item, add_popup_submenu, add_popup_separator, g_menu);
00386 
00387     gtk_widget_show(g_menu);
00388     // gtk_widget_realize(g_menu);
00389 }
00390 
00391 
00392 static gboolean update_display(gpointer data)
00393 {
00394 #if (TIMING_ON)
00395     stop_timer(__func__);
00396 #endif    
00397     display_update_return_control( (gint) data);
00398     return FALSE; // don't call again
00399 }
00400 
00401 
00402 static void idle_update_display(gint type)
00403 {
00404     g_idle_add(update_display, (gpointer) type);
00405 }
00406 
00407 
00408 static void set_active(gboolean do_active)
00409 {
00410     if (do_active == is_active) return;
00411 
00412     if (do_active)
00413     {
00414 #if (TIMING_ON)
00415         start_timer();
00416 #endif        
00417         display_gain_control();
00418         create_menu();
00419         gtk_menu_popup(GTK_MENU(g_menu), NULL, NULL, menu_set_position, NULL, 0, 0);
00420         idle_update_display(DM_HINT_PARTIAL);
00421     }
00422     else
00423     {
00424         gtk_menu_popdown(GTK_MENU(g_menu));
00425     }
00426     
00427     is_active = do_active;
00428 }
00429 
Generated by  doxygen 1.6.2-20100208