~helene-verhaeghe27/cairo-dock-core/bugfix

« back to all changes in this revision

Viewing changes to Help/src/applet-tips-dialog.c

  • Committer: Fabrice Rey
  • Date: 2013-02-02 18:41:38 UTC
  • Revision ID: fabounet03@gmail.com-20130202184138-n2eu2i9g0bmy40ru
made the Help module as an independant applet + removed the need for RTLD_DEEPBIND, which should make the dock compatible with BSD again

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
* This file is a part of the Cairo-Dock project
 
3
*
 
4
* Copyright : (C) see the 'copyright' file.
 
5
* E-mail    : see the 'copyright' file.
 
6
*
 
7
* This program is free software; you can redistribute it and/or
 
8
* modify it under the terms of the GNU General Public License
 
9
* as published by the Free Software Foundation; either version 3
 
10
* of the License, or (at your option) any later version.
 
11
*
 
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.
 
16
* You should have received a copy of the GNU General Public License
 
17
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
*/
 
19
 
 
20
#include <stdlib.h>
 
21
#include <string.h>
 
22
 
 
23
#include "applet-struct.h"
 
24
#include "applet-tips-dialog.h"
 
25
 
 
26
static void _on_tips_category_changed (GtkComboBox *pWidget, gpointer *data);
 
27
 
 
28
typedef struct {
 
29
        GKeyFile *pKeyFile;
 
30
        gchar **pGroupList;
 
31
        gint iNbGroups;
 
32
        gchar **pKeyList;  // keys of the current group
 
33
        gsize iNbKeys;
 
34
        gint iNumTipGroup;  // current group being displayed.
 
35
        gint iNumTipKey;  // current key being displayed.
 
36
        GtkWidget *pCategoryCombo;
 
37
        } CDTipsData;
 
38
 
 
39
static void _cairo_dock_get_next_tip (CDTipsData *pTips)
 
40
{
 
41
        pTips->iNumTipKey ++;  // skip the current expander to go to the current label, which will be skipped in the first iteration.
 
42
        const gchar *cGroupName = pTips->pGroupList[pTips->iNumTipGroup];
 
43
        gboolean bOk;
 
44
        do
 
45
        {
 
46
                pTips->iNumTipKey ++;
 
47
                if (pTips->iNumTipKey >= (gint) pTips->iNbKeys)  // no more key, go to next group.
 
48
                {
 
49
                        pTips->iNumTipGroup ++;
 
50
                        if (pTips->iNumTipGroup >= pTips->iNbGroups)  // no more group, restart from first group.
 
51
                                pTips->iNumTipGroup = 0;
 
52
                        pTips->iNumTipKey = 0;
 
53
                        
 
54
                        // since the group has changed, get the keys again.
 
55
                        g_strfreev (pTips->pKeyList);
 
56
                        cGroupName = pTips->pGroupList[pTips->iNumTipGroup];
 
57
                        pTips->pKeyList = g_key_file_get_keys (pTips->pKeyFile, cGroupName, &pTips->iNbKeys, NULL);
 
58
                        
 
59
                        // and update the category in the comb
 
60
                        g_signal_handlers_block_matched (pTips->pCategoryCombo,
 
61
                                G_SIGNAL_MATCH_FUNC,
 
62
                                0,
 
63
                                0,
 
64
                                0,
 
65
                                _on_tips_category_changed,
 
66
                                NULL);
 
67
                        gtk_combo_box_set_active (GTK_COMBO_BOX (pTips->pCategoryCombo), pTips->iNumTipGroup);
 
68
                        g_signal_handlers_unblock_matched (pTips->pCategoryCombo,
 
69
                                G_SIGNAL_MATCH_FUNC,
 
70
                                0,
 
71
                                0,
 
72
                                0,
 
73
                                _on_tips_category_changed,
 
74
                                NULL);
 
75
                }
 
76
                
 
77
                // check if the key is an expander widget.
 
78
                const gchar *cKeyName = pTips->pKeyList[pTips->iNumTipKey];
 
79
                gchar *cKeyComment =  g_key_file_get_comment (pTips->pKeyFile, cGroupName, cKeyName, NULL);
 
80
                bOk = (cKeyComment && *cKeyComment == CAIRO_DOCK_WIDGET_EXPANDER);  // whether it's an expander.
 
81
                g_free (cKeyComment);
 
82
        } while (!bOk);
 
83
}
 
84
 
 
85
static void _cairo_dock_get_previous_tip (CDTipsData *pTips)
 
86
{
 
87
        pTips->iNumTipKey --;
 
88
        
 
89
        const gchar *cGroupName = pTips->pGroupList[pTips->iNumTipGroup];
 
90
        gboolean bOk;
 
91
        do
 
92
        {
 
93
                pTips->iNumTipKey --;
 
94
                if (pTips->iNumTipKey < 0)  // no more key, go to previous group.
 
95
                {
 
96
                        pTips->iNumTipGroup --;
 
97
                        if (pTips->iNumTipGroup < 0)  // no more group, restart from the last group.
 
98
                                pTips->iNumTipGroup = pTips->iNbGroups - 1;
 
99
                        
 
100
                        // since the group has changed, get the keys again.
 
101
                        g_strfreev (pTips->pKeyList);
 
102
                        cGroupName = pTips->pGroupList[pTips->iNumTipGroup];
 
103
                        pTips->pKeyList = g_key_file_get_keys (pTips->pKeyFile, cGroupName, &pTips->iNbKeys, NULL);
 
104
 
 
105
                        pTips->iNumTipKey = pTips->iNbKeys - 2;
 
106
                        
 
107
                        // and update the category in the comb
 
108
                        g_signal_handlers_block_matched (pTips->pCategoryCombo,
 
109
                                G_SIGNAL_MATCH_FUNC,
 
110
                                0,
 
111
                                0,
 
112
                                0,
 
113
                                _on_tips_category_changed,
 
114
                                NULL);
 
115
                        gtk_combo_box_set_active (GTK_COMBO_BOX (pTips->pCategoryCombo), pTips->iNumTipGroup);
 
116
                        g_signal_handlers_unblock_matched (pTips->pCategoryCombo,
 
117
                                G_SIGNAL_MATCH_FUNC,
 
118
                                0,
 
119
                                0,
 
120
                                0,
 
121
                                _on_tips_category_changed,
 
122
                                NULL);
 
123
                }
 
124
                
 
125
                // check if the key is an expander widget.
 
126
                const gchar *cKeyName = pTips->pKeyList[pTips->iNumTipKey];
 
127
                gchar *cKeyComment =  g_key_file_get_comment (pTips->pKeyFile, cGroupName, cKeyName, NULL);
 
128
                bOk = (cKeyComment && *cKeyComment == CAIRO_DOCK_WIDGET_EXPANDER);  // whether it's an expander.
 
129
        } while (!bOk);
 
130
}
 
131
 
 
132
static gchar *_build_tip_text (CDTipsData *pTips)
 
133
{
 
134
        const gchar *cGroupName = pTips->pGroupList[pTips->iNumTipGroup];
 
135
        const gchar *cKeyName1 = pTips->pKeyList[pTips->iNumTipKey];
 
136
        const gchar *cKeyName2 = pTips->pKeyList[pTips->iNumTipKey+1];
 
137
        
 
138
        char iElementType;
 
139
        guint iNbElements = 0;
 
140
        gboolean bAligned;
 
141
        const gchar *cHint1 = NULL;  // points on the comment.
 
142
        gchar **pAuthorizedValuesList1 = NULL;
 
143
        gchar *cKeyComment1 =  g_key_file_get_comment (pTips->pKeyFile, cGroupName, cKeyName1, NULL);
 
144
        cairo_dock_parse_key_comment (cKeyComment1, &iElementType, &iNbElements, &pAuthorizedValuesList1, &bAligned, &cHint1);  // points on the comment.
 
145
        
 
146
        const gchar *cHint2 = NULL;
 
147
        gchar **pAuthorizedValuesList2 = NULL;
 
148
        gchar *cKeyComment2 =  g_key_file_get_comment (pTips->pKeyFile, cGroupName, cKeyName2, NULL);
 
149
        const gchar *cText2 = cairo_dock_parse_key_comment (cKeyComment2, &iElementType, &iNbElements, &pAuthorizedValuesList2, &bAligned, &cHint2);
 
150
        
 
151
        gchar *cText = g_strdup_printf ("<b>%s</b>\n\n<i>%s</i>\n\n%s",
 
152
                _("Tips and Tricks"),
 
153
                (pAuthorizedValuesList1 ? gettext (pAuthorizedValuesList1[0]) : ""),
 
154
                gettext (cText2));
 
155
        
 
156
        g_strfreev (pAuthorizedValuesList1);
 
157
        g_strfreev (pAuthorizedValuesList2);
 
158
        g_free (cKeyComment1);
 
159
        g_free (cKeyComment2);
 
160
        return cText;
 
161
}
 
162
static void _update_tip_text (CDTipsData *pTips, CairoDialog *pDialog)
 
163
{
 
164
        gchar *cText = _build_tip_text (pTips);
 
165
        
 
166
        cairo_dock_set_dialog_message (pDialog, cText);
 
167
        
 
168
        g_free (cText);
 
169
}
 
170
static void _tips_dialog_action (int iClickedButton, G_GNUC_UNUSED GtkWidget *pInteractiveWidget, CDTipsData *pTips, CairoDialog *pDialog)
 
171
{
 
172
        cd_debug ("%s (%d)", __func__, iClickedButton);
 
173
        if (iClickedButton == 2 || iClickedButton == -1)  // click on "next", or Enter.
 
174
        {
 
175
                // show the next tip
 
176
                _cairo_dock_get_next_tip (pTips);
 
177
                
 
178
                _update_tip_text (pTips, pDialog);
 
179
                
 
180
                cairo_dock_dialog_reference (pDialog);  // keep the dialog alive.
 
181
        }
 
182
        else if (iClickedButton == 1)  // click on "previous"
 
183
        {
 
184
                // show the previous tip
 
185
                _cairo_dock_get_previous_tip (pTips);
 
186
                
 
187
                _update_tip_text (pTips, pDialog);
 
188
                
 
189
                cairo_dock_dialog_reference (pDialog);  // keep the dialog alive.
 
190
        }
 
191
        else  // click on "close" or Escape
 
192
        {
 
193
                myData.iLastTipGroup = pTips->iNumTipGroup;
 
194
                myData.iLastTipKey = pTips->iNumTipKey;
 
195
                gchar *cConfFilePath = g_strdup_printf ("%s/.help", g_cCairoDockDataDir);
 
196
                cairo_dock_update_conf_file (cConfFilePath,
 
197
                        G_TYPE_INT, "Last Tip", "group", pTips->iNumTipGroup,
 
198
                        G_TYPE_INT, "Last Tip", "key", pTips->iNumTipKey,
 
199
                        G_TYPE_INVALID);
 
200
                g_free (cConfFilePath);
 
201
        }
 
202
        cd_debug ("tips : %d/%d", pTips->iNumTipGroup, pTips->iNumTipKey);
 
203
}
 
204
static void _on_free_tips_dialog (CDTipsData *pTips)
 
205
{
 
206
        g_key_file_free (pTips->pKeyFile);
 
207
        g_strfreev (pTips->pGroupList);
 
208
        g_strfreev (pTips->pKeyList);
 
209
        g_free (pTips);
 
210
}
 
211
 
 
212
static void _on_tips_category_changed (GtkComboBox *pWidget, gpointer *data)
 
213
{
 
214
        CDTipsData *pTips = data[0];
 
215
        CairoDialog *pDialog = data[1];
 
216
        
 
217
        int iNumItem = gtk_combo_box_get_active (pWidget);
 
218
        g_return_if_fail (iNumItem < pTips->iNbGroups);
 
219
        
 
220
        pTips->iNumTipGroup = iNumItem;
 
221
        
 
222
        // since the group has changed, get the keys again.
 
223
        g_strfreev (pTips->pKeyList);
 
224
        const gchar *cGroupName = pTips->pGroupList[pTips->iNumTipGroup];
 
225
        pTips->pKeyList = g_key_file_get_keys (pTips->pKeyFile, cGroupName, &pTips->iNbKeys, NULL);
 
226
        pTips->iNumTipKey = 0;
 
227
        
 
228
        _update_tip_text (pTips, pDialog);
 
229
}
 
230
 
 
231
void cairo_dock_show_tips (void)
 
232
{
 
233
        if (myData.iSidGetParams != 0)
 
234
                return;
 
235
        
 
236
        // open the tips file
 
237
        const gchar *cConfFilePath = CD_APPLET_MY_CONF_FILE;
 
238
        GKeyFile *pKeyFile = cairo_dock_open_key_file (cConfFilePath);
 
239
        g_return_if_fail (pKeyFile != NULL);
 
240
        
 
241
        gsize iNbGroups = 0;
 
242
        gchar **pGroupList = g_key_file_get_groups (pKeyFile, &iNbGroups);
 
243
        iNbGroups -= 4;   // skip the last 4 groups (Troubleshooting and Contribute + Icon and Desklet).
 
244
        g_return_if_fail (pGroupList != NULL && iNbGroups > 0);
 
245
        
 
246
        // get the last displayed tip.
 
247
        guint iNumTipGroup, iNumTipKey;
 
248
        if (myData.iLastTipGroup < 0 || myData.iLastTipKey < 0)  // first time we display a tip.
 
249
        {
 
250
                iNumTipGroup = iNumTipKey = 0;
 
251
        }
 
252
        else
 
253
        {
 
254
                iNumTipGroup = myData.iLastTipGroup;
 
255
                iNumTipKey = myData.iLastTipKey;
 
256
                if (iNumTipGroup >= iNbGroups)  // be sure to stay inside the limits.
 
257
                {
 
258
                        iNumTipGroup = iNbGroups - 1;
 
259
                        iNumTipKey = 0;
 
260
                }
 
261
        }
 
262
        const gchar *cGroupName = pGroupList[iNumTipGroup];
 
263
        
 
264
        gsize iNbKeys = 0;
 
265
        gchar **pKeyList = g_key_file_get_keys (pKeyFile, cGroupName, &iNbKeys, NULL);
 
266
        g_return_if_fail (pKeyList != NULL && iNbKeys > 0);
 
267
        if (iNumTipKey >= iNbKeys)  // be sure to stay inside the limits.
 
268
                iNumTipKey = 0;
 
269
        
 
270
        CDTipsData *pTips = g_new0 (CDTipsData, 1);
 
271
        pTips->pKeyFile = pKeyFile;
 
272
        pTips->pGroupList = pGroupList;
 
273
        pTips->iNbGroups = iNbGroups;
 
274
        pTips->pKeyList = pKeyList;
 
275
        pTips->iNbKeys = iNbKeys;
 
276
        pTips->iNumTipGroup = iNumTipGroup;
 
277
        pTips->iNumTipKey = iNumTipKey;
 
278
        
 
279
        // update to the next tip.
 
280
        if (myData.iLastTipGroup >= 0 && myData.iLastTipKey >= 0)  // a previous tip exist => take the next one;
 
281
                _cairo_dock_get_next_tip (pTips);
 
282
        
 
283
        // build a list of the available groups.
 
284
        GtkWidget *pInteractiveWidget = _gtk_vbox_new (3);
 
285
        #if (GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 24)
 
286
        GtkWidget *pComboBox = gtk_combo_box_new_text ();
 
287
        #else
 
288
        GtkWidget *pComboBox = gtk_combo_box_text_new ();
 
289
        #endif
 
290
        guint i;
 
291
        for (i = 0; i < iNbGroups; i ++)
 
292
        {
 
293
                #if (GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 24)
 
294
                gtk_combo_box_append_text (GTK_COMBO_BOX (pComboBox), gettext (pGroupList[i]));
 
295
                #else
 
296
                gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (pComboBox), gettext (pGroupList[i]));
 
297
                #endif
 
298
        }
 
299
        gtk_combo_box_set_active (GTK_COMBO_BOX (pComboBox), pTips->iNumTipGroup);
 
300
        pTips->pCategoryCombo = pComboBox;
 
301
        static gpointer data_combo[2];
 
302
        data_combo[0] = pTips;  // the 2nd data is the dialog, we'll set it after we make it.
 
303
        g_signal_connect (G_OBJECT (pComboBox), "changed", G_CALLBACK(_on_tips_category_changed), data_combo);
 
304
        GtkWidget *pJumpBox = _gtk_hbox_new (3);
 
305
        GtkWidget *label = gtk_label_new (_("Category"));
 
306
        cairo_dock_set_dialog_widget_text_color (label);
 
307
        gtk_box_pack_end (GTK_BOX (pJumpBox), pComboBox, FALSE, FALSE, 0);
 
308
        gtk_box_pack_end (GTK_BOX (pJumpBox), label, FALSE, FALSE, 0);
 
309
        gtk_box_pack_start (GTK_BOX (pInteractiveWidget), pJumpBox, FALSE, FALSE, 0);
 
310
        
 
311
        // build the dialog.
 
312
        gchar *cText = _build_tip_text (pTips);
 
313
        CairoDialogAttribute attr;
 
314
        memset (&attr, 0, sizeof (CairoDialogAttribute));
 
315
        attr.cText = cText;
 
316
        attr.cImageFilePath = NULL;
 
317
        attr.pInteractiveWidget = pInteractiveWidget;
 
318
        attr.pActionFunc = (CairoDockActionOnAnswerFunc)_tips_dialog_action;
 
319
        attr.pUserData = pTips;
 
320
        attr.pFreeDataFunc = (GFreeFunc)_on_free_tips_dialog;
 
321
        const gchar *cButtons[] = {"cancel", GTK_STOCK_GO_FORWARD"-rtl", GTK_STOCK_GO_FORWARD"-ltr", NULL};
 
322
        attr.cButtonsImage = cButtons;
 
323
        attr.bUseMarkup = TRUE;
 
324
        
 
325
        CairoDialog *pTipsDialog = cairo_dock_build_dialog (&attr, myIcon, myContainer);
 
326
        
 
327
        data_combo[1] = pTipsDialog;
 
328
        
 
329
        g_free (cText);
 
330
}