~midori/midori/gtk3WebKit2only

« back to all changes in this revision

Viewing changes to src/sokoke.c

  • Committer: Christian Dywan
  • Date: 2007-12-16 22:20:24 UTC
  • Revision ID: git-v1:3bbd273a4f9e85a1d8380cb0924c875683fa3ad1
Tags: v0.0.14
Initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
 
3
 
 
4
 This library is free software; you can redistribute it and/or
 
5
 modify it under the terms of the GNU Lesser General Public
 
6
 License as published by the Free Software Foundation; either
 
7
 version 2.1 of the License, or (at your option) any later version.
 
8
 
 
9
 See the file COPYING for the full license text.
 
10
*/
 
11
 
 
12
#include "sokoke.h"
 
13
 
 
14
#include "debug.h"
 
15
 
 
16
#include <string.h>
 
17
#ifdef HAVE_UNISTD_H
 
18
    #include <unistd.h>
 
19
#endif
 
20
#include <gdk/gdkkeysyms.h>
 
21
 
 
22
void sokoke_combo_box_add_strings(GtkComboBox* combobox
 
23
 , const gchar* sLabelFirst, ...)
 
24
{
 
25
    // Add a number of strings to a combobox, terminated with NULL
 
26
    // This works only for text comboboxes
 
27
    va_list args;
 
28
    va_start(args, sLabelFirst);
 
29
 
 
30
    const gchar* sLabel;
 
31
    for(sLabel = sLabelFirst; sLabel; sLabel = va_arg(args, const gchar*))
 
32
        gtk_combo_box_append_text(combobox, sLabel);
 
33
 
 
34
    va_end(args);
 
35
}
 
36
 
 
37
void sokoke_radio_action_set_current_value(GtkRadioAction* action
 
38
 , gint current_value)
 
39
{
 
40
    // Activates the group member with the given value
 
41
    #if GTK_CHECK_VERSION(2, 10, 0)
 
42
    gtk_radio_action_set_current_value(action, current_value);
 
43
    #else
 
44
    // TODO: Implement this for older gtk
 
45
    UNIMPLEMENTED
 
46
    #endif
 
47
}
 
48
 
 
49
void sokoke_widget_set_visible(GtkWidget* widget, gboolean bVisibility)
 
50
{
 
51
    // Show or hide the widget
 
52
    if(bVisibility)
 
53
        gtk_widget_show(widget);
 
54
    else
 
55
        gtk_widget_hide(widget);
 
56
}
 
57
 
 
58
void sokoke_container_show_children(GtkContainer* container)
 
59
{
 
60
    // Show every child but not the container itself
 
61
    gtk_container_foreach(container, (GtkCallback)(gtk_widget_show_all), NULL);
 
62
}
 
63
 
 
64
void sokoke_widget_set_tooltip_text(GtkWidget* widget, const gchar* sText)
 
65
{
 
66
    #if GTK_CHECK_VERSION(2, 12, 0)
 
67
    gtk_widget_set_tooltip_text(widget, sText);
 
68
    #else
 
69
    static GtkTooltips* tooltips;
 
70
    if(!tooltips)
 
71
        tooltips = gtk_tooltips_new();
 
72
    gtk_tooltips_set_tip(tooltips, widget, sText, NULL);
 
73
    #endif
 
74
}
 
75
 
 
76
void sokoke_tool_item_set_tooltip_text(GtkToolItem* toolitem, const gchar* sText)
 
77
{
 
78
    // TODO: Use 2.12 api if available
 
79
    GtkTooltips* tooltips = gtk_tooltips_new();
 
80
    gtk_tool_item_set_tooltip(toolitem, tooltips, sText, NULL);
 
81
}
 
82
 
 
83
void sokoke_widget_popup(GtkWidget* widget, GtkMenu* menu
 
84
 , GdkEventButton* event)
 
85
{
 
86
    // TODO: Provide a GtkMenuPositionFunc in case a keyboard invoked this
 
87
    int button, event_time;
 
88
    if(event)
 
89
    {
 
90
        button = event->button;
 
91
        event_time = event->time;
 
92
    }
 
93
    else
 
94
    {
 
95
        button = 0;
 
96
        event_time = gtk_get_current_event_time();
 
97
    }
 
98
 
 
99
    if(!gtk_menu_get_attach_widget(menu))
 
100
        gtk_menu_attach_to_widget(menu, widget, NULL);
 
101
    gtk_menu_popup(menu, NULL, NULL, NULL, NULL, button, event_time);
 
102
}
 
103
 
 
104
enum
 
105
{
 
106
 SOKOKE_DESKTOP_UNKNOWN,
 
107
 SOKOKE_DESKTOP_XFCE
 
108
};
 
109
 
 
110
static guint sokoke_get_desktop(void)
 
111
{
 
112
    // Are we running in Xfce?
 
113
    gint iResult; gchar* stdout; gchar* stderr;
 
114
    gboolean bSuccess = g_spawn_command_line_sync(
 
115
     "xprop -root _DT_SAVE_MODE | grep -q xfce4"
 
116
     , &stdout, &stderr, &iResult, NULL);
 
117
    if(bSuccess && !iResult)
 
118
        return SOKOKE_DESKTOP_XFCE;
 
119
 
 
120
    return SOKOKE_DESKTOP_UNKNOWN;
 
121
}
 
122
 
 
123
gpointer sokoke_xfce_header_new(const gchar* sIcon, const gchar* sTitle)
 
124
{
 
125
 
 
126
    // Create an xfce header with icon and title
 
127
    // This returns NULL if the desktop is not xfce
 
128
    if(sokoke_get_desktop() == SOKOKE_DESKTOP_XFCE)
 
129
    {
 
130
        GtkWidget* entry = gtk_entry_new();
 
131
        gchar* sMarkup;
 
132
        GtkWidget* xfce_heading = gtk_event_box_new();
 
133
        gtk_widget_modify_bg(xfce_heading, GTK_STATE_NORMAL
 
134
         , &entry->style->base[GTK_STATE_NORMAL]);
 
135
        GtkWidget* hbox = gtk_hbox_new(FALSE, 12);
 
136
        gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
 
137
        GtkWidget* icon = gtk_image_new_from_icon_name(sIcon, GTK_ICON_SIZE_DIALOG);
 
138
        gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0);
 
139
        GtkWidget* label = gtk_label_new(NULL);
 
140
        gtk_widget_modify_fg(label, GTK_STATE_NORMAL
 
141
         , &entry->style->text[GTK_STATE_NORMAL]);
 
142
        sMarkup = g_strdup_printf("<span size='large' weight='bold'>%s</span>", sTitle);
 
143
        gtk_label_set_markup(GTK_LABEL(label), sMarkup);
 
144
        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
 
145
        gtk_container_add(GTK_CONTAINER(xfce_heading), hbox);
 
146
        g_free(sMarkup);
 
147
        return xfce_heading;
 
148
    }
 
149
    return NULL;
 
150
}
 
151
 
 
152
gpointer sokoke_superuser_warning_new(void)
 
153
{
 
154
    // Create a horizontal bar with a security warning
 
155
    // This returns NULL if the user is no superuser
 
156
    #ifdef HAVE_UNISTD_H
 
157
    if(G_UNLIKELY(!geteuid())) // effective superuser?
 
158
    {
 
159
        GtkWidget* hbox = gtk_event_box_new();
 
160
        gtk_widget_modify_bg(hbox, GTK_STATE_NORMAL
 
161
         , &hbox->style->bg[GTK_STATE_SELECTED]);
 
162
        GtkWidget* label = gtk_label_new("Warning: You are using the superuser account!");
 
163
        gtk_misc_set_padding(GTK_MISC(label), 0, 2);
 
164
        gtk_widget_modify_fg(GTK_WIDGET(label), GTK_STATE_NORMAL
 
165
         , &GTK_WIDGET(label)->style->fg[GTK_STATE_SELECTED]);
 
166
        gtk_container_add(GTK_CONTAINER(hbox), GTK_WIDGET(label));
 
167
        return hbox;
 
168
    }
 
169
    #endif
 
170
    return NULL;
 
171
}
 
172
 
 
173
GtkWidget* sokoke_hig_frame_new(const gchar* sLabel)
 
174
{
 
175
    // Create a frame with no actual frame but a bold label and indentation
 
176
    GtkWidget* frame = gtk_frame_new(NULL);
 
177
    gchar* sLabelBold = g_strdup_printf("<b>%s</b>", sLabel);
 
178
    GtkWidget* label = gtk_label_new(NULL);
 
179
    gtk_label_set_markup(GTK_LABEL(label), sLabelBold);
 
180
    g_free(sLabelBold);
 
181
    gtk_frame_set_label_widget(GTK_FRAME(frame), label);
 
182
    gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
 
183
    return frame;
 
184
}
 
185
 
 
186
void sokoke_widget_set_pango_font_style(GtkWidget* widget, PangoStyle style)
 
187
{
 
188
    // Conveniently change the pango font style
 
189
    // For some reason we need to reset if we actually want the normal style
 
190
    if(style == PANGO_STYLE_NORMAL)
 
191
        gtk_widget_modify_font(widget, NULL);
 
192
    else
 
193
    {
 
194
        PangoFontDescription* pangofontdesc = pango_font_description_new();
 
195
        pango_font_description_set_style(pangofontdesc, PANGO_STYLE_ITALIC);
 
196
        gtk_widget_modify_font(widget, pangofontdesc);
 
197
        pango_font_description_free(pangofontdesc);
 
198
    }
 
199
}
 
200
 
 
201
static gboolean sokoke_on_entry_focus_in_event(GtkEntry* entry, GdkEventFocus *event
 
202
 , gpointer userdata)
 
203
{
 
204
    gboolean bDefaultText = (gboolean)g_object_get_data(G_OBJECT(entry)
 
205
     , "sokoke_bDefaultText");
 
206
    if(bDefaultText)
 
207
    {
 
208
        gtk_entry_set_text(entry, "");
 
209
        g_object_set_data(G_OBJECT(entry), "sokoke_bDefaultText", (gpointer)FALSE);
 
210
        sokoke_widget_set_pango_font_style(GTK_WIDGET(entry), PANGO_STYLE_NORMAL);
 
211
    }
 
212
    return FALSE;
 
213
}
 
214
 
 
215
static gboolean sokoke_on_entry_focus_out_event(GtkEntry* entry, GdkEventFocus* event
 
216
 , gpointer userdata)
 
217
{
 
218
    const gchar* sText = gtk_entry_get_text(entry);
 
219
    if(sText[0] == '\0')
 
220
    {
 
221
        const gchar* sDefaultText = (const gchar*)g_object_get_data(
 
222
         G_OBJECT(entry), "sokoke_sDefaultText");
 
223
        gtk_entry_set_text(entry, sDefaultText);
 
224
        g_object_set_data(G_OBJECT(entry), "sokoke_bDefaultText", (gpointer)TRUE);
 
225
        sokoke_widget_set_pango_font_style(GTK_WIDGET(entry), PANGO_STYLE_ITALIC);
 
226
    }
 
227
    return FALSE;
 
228
}
 
229
 
 
230
void sokoke_entry_set_default_text(GtkEntry* entry, const gchar* sDefaultText)
 
231
{
 
232
    // Note: The default text initially overwrites any previous text
 
233
    gchar* sOldValue = g_object_get_data(G_OBJECT(entry), "sokoke_sDefaultText");
 
234
    if(!sOldValue)
 
235
    {
 
236
        g_object_set_data(G_OBJECT(entry), "sokoke_bDefaultText", (gpointer)TRUE);
 
237
        sokoke_widget_set_pango_font_style(GTK_WIDGET(entry), PANGO_STYLE_ITALIC);
 
238
        gtk_entry_set_text(entry, sDefaultText);
 
239
    }
 
240
    g_object_set_data(G_OBJECT(entry), "sokoke_sDefaultText", (gpointer)sDefaultText);
 
241
    g_signal_connect(entry, "focus-in-event"
 
242
     , G_CALLBACK(sokoke_on_entry_focus_in_event), NULL);
 
243
    g_signal_connect(entry, "focus-out-event"
 
244
     , G_CALLBACK(sokoke_on_entry_focus_out_event), NULL);
 
245
}
 
246
 
 
247
gchar* sokoke_key_file_get_string_default(GKeyFile* key_file
 
248
 , const gchar* group_name, const gchar* key, const gchar* def, GError* *error)
 
249
{
 
250
    gchar* value = g_key_file_get_string(key_file, group_name, key, error);
 
251
    return value == NULL ? g_strdup(def) : value;
 
252
}
 
253
 
 
254
gint sokoke_key_file_get_integer_default(GKeyFile* key_file
 
255
 , const gchar* group_name, const gchar* key, const gint def, GError** error)
 
256
{
 
257
    if(!g_key_file_has_key(key_file, group_name, key, NULL))
 
258
        return def;
 
259
    return g_key_file_get_integer(key_file, group_name, key, error);
 
260
}
 
261
 
 
262
gboolean sokoke_key_file_save_to_file(GKeyFile* key_file
 
263
 , const gchar* sFilename, GError** error)
 
264
{
 
265
    gchar* sData = g_key_file_to_data(key_file, NULL, error);
 
266
    if(!sData)
 
267
        return FALSE;
 
268
    FILE* fp;
 
269
    if(!(fp = fopen(sFilename, "w")))
 
270
    {
 
271
        *error = g_error_new(G_FILE_ERROR, G_FILE_ERROR_ACCES
 
272
         , "Writing failed.");
 
273
        return FALSE;
 
274
    }
 
275
    fputs(sData, fp);
 
276
    fclose(fp);
 
277
    g_free(sData);
 
278
    return TRUE;
 
279
}
 
280
 
 
281
void sokoke_widget_get_text_size(GtkWidget* widget, const gchar* sText
 
282
 , gint* w, gint* h)
 
283
{
 
284
    PangoLayout* layout = gtk_widget_create_pango_layout(widget, sText);
 
285
    pango_layout_get_pixel_size(layout, w, h);
 
286
    g_object_unref(layout);
 
287
}
 
288
 
 
289
void sokoke_menu_item_set_accel(GtkMenuItem* menuitem, const gchar* sPath
 
290
 , const gchar* sKey, GdkModifierType accel_mods)
 
291
{
 
292
    if(sPath && *sPath)
 
293
    {
 
294
        gchar* path = g_strconcat("<", g_get_prgname(), ">/", sPath, NULL);
 
295
        gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuitem), path);
 
296
        guint keyVal = sKey ? gdk_keyval_from_name(sKey) : 0;
 
297
        gtk_accel_map_add_entry(path, keyVal, accel_mods);
 
298
        g_free(path);
 
299
    }
 
300
}
 
301
 
 
302
gboolean sokoke_entry_can_undo(GtkEntry* entry)
 
303
{
 
304
    // TODO: Can we undo the last input?
 
305
    return FALSE;
 
306
}
 
307
 
 
308
gboolean sokoke_entry_can_redo(GtkEntry* entry)
 
309
{
 
310
    // TODO: Can we redo the last input?
 
311
    return FALSE;
 
312
}
 
313
 
 
314
void sokoke_entry_undo(GtkEntry* entry)
 
315
{
 
316
    // TODO: Implement undo
 
317
    UNIMPLEMENTED
 
318
}
 
319
 
 
320
void sokoke_entry_redo(GtkEntry* entry)
 
321
{
 
322
    // TODO: Implement redo
 
323
    UNIMPLEMENTED
 
324
}
 
325
 
 
326
static gboolean sokoke_on_undo_entry_key_down(GtkEntry* widget, GdkEventKey* event
 
327
 , gpointer userdata)
 
328
{
 
329
    switch(event->keyval)
 
330
    {
 
331
    case GDK_Undo:
 
332
        sokoke_entry_undo(widget);
 
333
        return FALSE;
 
334
    case GDK_Redo:
 
335
        sokoke_entry_redo(widget);
 
336
        return FALSE;
 
337
    default:
 
338
        return FALSE;
 
339
    }
 
340
}
 
341
 
 
342
static void sokoke_on_undo_entry_populate_popup(GtkEntry* entry, GtkMenu* menu
 
343
 , gpointer userdata)
 
344
{
 
345
    // Enhance the entry's menu with undo and redo items.
 
346
    GtkWidget* menuitem = gtk_separator_menu_item_new();
 
347
    gtk_menu_shell_prepend((GtkMenuShell*)menu, menuitem);
 
348
    gtk_widget_show(menuitem);
 
349
    menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_REDO, NULL);
 
350
    g_signal_connect(menuitem, "activate", G_CALLBACK(sokoke_entry_redo), userdata);
 
351
    gtk_widget_set_sensitive(menuitem, sokoke_entry_can_redo(entry));
 
352
    gtk_menu_shell_prepend((GtkMenuShell*)menu, menuitem);
 
353
    gtk_widget_show(menuitem);
 
354
    menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_UNDO, NULL);
 
355
    g_signal_connect(menuitem, "activate", G_CALLBACK(sokoke_entry_undo), userdata);
 
356
    gtk_widget_set_sensitive(menuitem, sokoke_entry_can_undo(entry));
 
357
    gtk_menu_shell_prepend((GtkMenuShell*)menu, menuitem);
 
358
    gtk_widget_show(menuitem);
 
359
}
 
360
 
 
361
gboolean sokoke_entry_get_can_undo(GtkEntry* entry)
 
362
{
 
363
    // TODO: Is this entry undo enabled?
 
364
    return FALSE;
 
365
}
 
366
 
 
367
void sokoke_entry_set_can_undo(GtkEntry* entry, gboolean bCanUndo)
 
368
{
 
369
    if(bCanUndo)
 
370
    {
 
371
        g_signal_connect(entry, "key-press-event"
 
372
         , G_CALLBACK(sokoke_on_undo_entry_key_down), NULL);
 
373
        g_signal_connect(entry, "populate-popup"
 
374
         , G_CALLBACK(sokoke_on_undo_entry_populate_popup), NULL);
 
375
    }
 
376
    else
 
377
    {
 
378
        ; // TODO: disconnect signal
 
379
        UNIMPLEMENTED
 
380
    }
 
381
}