3 Minimum Profit - Programmer Text Editor
7 Copyright (C) 1991-2010 Angel Ortega <angel@triptico.com>
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 http://www.triptico.com
39 #include <gdk/gdkkeysyms.h>
52 static GtkWidget
*window
= NULL
;
53 static GtkWidget
*file_tabs
= NULL
;
54 static GtkWidget
*area
= NULL
;
55 static GtkWidget
*scrollbar
= NULL
;
56 static GtkWidget
*status
= NULL
;
57 static GtkWidget
*menu_bar
= NULL
;
58 static GdkGC
*gc
= NULL
;
59 static GtkIMContext
*im
= NULL
;
60 static GdkPixmap
*pixmap
= NULL
;
62 /* character read from the keyboard */
63 static wchar_t im_char
[2];
65 /* font information */
66 static int font_width
= 0;
67 static int font_height
= 0;
68 static PangoFontDescription
*font
= NULL
;
71 static GdkColor
*inks
= NULL
;
72 static GdkColor
*papers
= NULL
;
73 static int *underlines
= NULL
;
75 /* true if the selection is ours */
76 static int got_selection
= 0;
78 /* hack for active waiting for the selection */
79 static int wait_for_selection
= 0;
81 /* global modal status */
82 /* code for the 'normal' attribute */
83 static int normal_attr
= 0;
85 /* mp.drv.form() controls */
87 static GtkWidget
**form_widgets
= NULL
;
88 static mpdm_t form_args
= NULL
;
89 static mpdm_t form_values
= NULL
;
92 static int mouse_down
= 0;
95 static mpdm_t timer_func
= NULL
;
97 /* maximize wanted? */
98 static int maximize
= 0;
102 /** support functions **/
106 static char *wcs_to_utf8(const wchar_t * wptr
)
107 /* converts a wcs to utf-8 */
114 /* do the conversion */
115 ptr
= g_convert((const gchar
*) wptr
, (i
+ 1) * sizeof(wchar_t),
116 "UTF-8", "WCHAR_T", NULL
, &o
, NULL
);
122 static char *v_to_utf8(mpdm_t v
)
128 ptr
= wcs_to_utf8(mpdm_string(v
));
135 static wchar_t *utf8_to_wcs(const char *ptr
)
136 /* converts utf-8 to wcs */
143 /* do the conversion */
144 wptr
= (wchar_t *) g_convert((gchar
*) ptr
, i
+ 1,
145 "WCHAR_T", "UTF-8", NULL
, &o
, NULL
);
151 static void update_window_size(void)
152 /* updates the viewport size in characters */
158 /* get font metrics */
159 pa
= gtk_widget_create_pango_layout(area
, "m");
160 pango_layout_set_font_description(pa
, font
);
161 pango_layout_get_pixel_size(pa
, &font_width
, &font_height
);
164 /* calculate the size in chars */
165 tx
= (area
->allocation
.width
/ font_width
);
166 ty
= (area
->allocation
.height
/ font_height
) + 1;
168 /* store the 'window' size */
169 v
= mpdm_hget_s(mp
, L
"window");
170 mpdm_hset_s(v
, L
"tx", MPDM_I(tx
));
171 mpdm_hset_s(v
, L
"ty", MPDM_I(ty
));
173 /* rebuild the pixmap for the double buffer */
175 gdk_pixmap_unref(pixmap
);
177 pixmap
= gdk_pixmap_new(area
->window
,
178 area
->allocation
.width
, font_height
, -1);
182 static void build_fonts(void)
183 /* builds the fonts */
187 const char *font_face
= "Mono";
192 pango_font_description_free(font
);
194 /* get current configuration */
195 if ((c
= mpdm_hget_s(mp
, L
"config")) != NULL
) {
198 if ((v
= mpdm_hget_s(c
, L
"font_size")) != NULL
)
199 font_size
= mpdm_ival(v
);
201 mpdm_hset_s(c
, L
"font_size", MPDM_I(font_size
));
203 if ((v
= mpdm_hget_s(c
, L
"font_face")) != NULL
) {
204 w
= mpdm_ref(MPDM_2MBS(v
->data
));
208 mpdm_hset_s(c
, L
"font_face", MPDM_MBS(font_face
));
211 snprintf(tmp
, sizeof(tmp
) - 1, "%s %d", font_face
, font_size
);
212 tmp
[sizeof(tmp
) - 1] = '\0';
214 font
= pango_font_description_from_string(tmp
);
215 update_window_size();
221 static void build_color(GdkColor
* gdkcolor
, int rgb
)
225 gdkcolor
->blue
= (rgb
& 0x000000ff) << 8;
226 gdkcolor
->green
= (rgb
& 0x0000ff00);
227 gdkcolor
->red
= (rgb
& 0x00ff0000) >> 8;
228 gdk_colormap_alloc_color(gdk_colormap_get_system(), gdkcolor
, FALSE
,
233 static void build_colors(void)
234 /* builds the colors */
241 /* gets the color definitions and attribute names */
242 colors
= mpdm_hget_s(mp
, L
"colors");
243 l
= mpdm_ref(mpdm_keys(colors
));
246 /* redim the structures */
247 inks
= realloc(inks
, sizeof(GdkColor
) * s
);
248 papers
= realloc(papers
, sizeof(GdkColor
) * s
);
249 underlines
= realloc(underlines
, sizeof(int) * s
);
251 /* loop the colors */
252 for (n
= 0; n
< s
&& (c
= mpdm_aget(l
, n
)) != NULL
; n
++) {
253 mpdm_t d
= mpdm_hget(colors
, c
);
254 mpdm_t v
= mpdm_hget_s(d
, L
"gui");
256 /* store the 'normal' attribute */
257 if (wcscmp(mpdm_string(c
), L
"normal") == 0)
261 mpdm_hset_s(d
, L
"attr", MPDM_I(n
));
263 build_color(&inks
[n
], mpdm_ival(mpdm_aget(v
, 0)));
264 build_color(&papers
[n
], mpdm_ival(mpdm_aget(v
, 1)));
267 v
= mpdm_hget_s(d
, L
"flags");
268 underlines
[n
] = mpdm_seek_s(v
, L
"underline", 1) != -1 ? 1 : 0;
270 if (mpdm_seek_s(v
, L
"reverse", 1) != -1) {
283 /** menu functions **/
285 static void redraw(void);
287 static void menu_item_callback(mpdm_t action
)
288 /* menu click callback */
290 mp_process_action(action
);
293 if (mp_exit_requested
)
298 static void build_submenu(GtkWidget
* menu
, mpdm_t labels
)
299 /* build a submenu */
302 GtkWidget
*menu_item
;
306 for (n
= 0; n
< mpdm_size(labels
); n
++) {
308 mpdm_t v
= mpdm_aget(labels
, n
);
310 /* if the action is a separator... */
311 if (*((wchar_t *) v
->data
) == L
'-')
312 menu_item
= gtk_menu_item_new();
316 ptr
= v_to_utf8(mp_menu_label(v
));
317 menu_item
= gtk_menu_item_new_with_label(ptr
);
321 gtk_menu_append(GTK_MENU(menu
), menu_item
);
322 g_signal_connect_swapped(G_OBJECT(menu_item
), "activate",
323 G_CALLBACK(menu_item_callback
), v
);
324 gtk_widget_show(menu_item
);
331 static void build_menu(void)
332 /* builds the menu */
334 static mpdm_t prev_menu
= NULL
;
338 /* gets the current menu */
339 if ((m
= mpdm_hget_s(mp
, L
"menu")) == NULL
)
342 /* if it's the same, do nothing */
343 if (mpdm_cmp(m
, prev_menu
) == 0)
346 /* create a new menu */
347 menu_bar
= gtk_menu_bar_new();
349 for (n
= 0; n
< mpdm_size(m
); n
++) {
354 GtkWidget
*menu_item
;
357 /* get the label and the items */
358 mi
= mpdm_aget(m
, n
);
359 v
= mpdm_aget(mi
, 0);
361 if ((ptr
= v_to_utf8(mpdm_gettext(v
))) == NULL
)
364 /* change the & by _ for the mnemonic */
365 for (i
= 0; ptr
[i
]; i
++)
369 /* add the menu and the label */
370 menu
= gtk_menu_new();
371 menu_item
= gtk_menu_item_new_with_mnemonic(ptr
);
374 gtk_widget_show(menu_item
);
375 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item
), menu
);
376 gtk_menu_bar_append(GTK_MENU_BAR(menu_bar
), menu_item
);
378 /* now loop the items */
379 build_submenu(menu
, mpdm_aget(mi
, 1));
384 /** main area drawing functions **/
386 static void switch_page(GtkNotebook
* notebook
, GtkNotebookPage
* page
,
387 gint pg_num
, gpointer data
)
388 /* 'switch_page' handler (filetabs) */
390 /* sets the active one */
391 mpdm_hset_s(mp
, L
"active_i", MPDM_I(pg_num
));
393 gtk_widget_grab_focus(area
);
398 static void draw_filetabs(void)
399 /* draws the filetabs */
401 static mpdm_t last
= NULL
;
405 names
= mpdm_ref(mp_get_doc_names());
407 /* disconnect redraw signal to avoid infinite loops */
408 g_signal_handlers_disconnect_by_func(G_OBJECT(file_tabs
),
409 G_CALLBACK(switch_page
), NULL
);
411 /* is the list different from the previous one? */
412 if (mpdm_cmp(names
, last
) != 0) {
414 /* delete the current tabs */
415 for (n
= 0; n
< mpdm_size(last
); n
++)
416 gtk_notebook_remove_page(GTK_NOTEBOOK(file_tabs
), 0);
418 /* create the new ones */
419 for (n
= 0; n
< mpdm_size(names
); n
++) {
423 mpdm_t v
= mpdm_aget(names
, n
);
425 if ((ptr
= v_to_utf8(v
)) != NULL
) {
426 p
= gtk_label_new(ptr
);
429 f
= gtk_frame_new(NULL
);
432 gtk_notebook_append_page(GTK_NOTEBOOK(file_tabs
), f
, p
);
438 /* store for the next time */
440 last
= mpdm_ref(names
);
445 /* set the active one */
446 gtk_notebook_set_page(GTK_NOTEBOOK(file_tabs
),
447 mpdm_ival(mpdm_hget_s(mp
, L
"active_i")));
449 /* reconnect signal */
450 g_signal_connect(G_OBJECT(file_tabs
), "switch_page",
451 G_CALLBACK(switch_page
), NULL
);
453 gtk_widget_grab_focus(area
);
457 static void draw_status(void)
458 /* draws the status line */
462 if ((ptr
= v_to_utf8(mp_build_status_line())) != NULL
) {
463 gtk_label_set_text(GTK_LABEL(status
), ptr
);
469 static gint
scroll_event(GtkWidget
* widget
, GdkEventScroll
* event
)
470 /* 'scroll_event' handler (mouse wheel) */
474 switch (event
->direction
) {
476 ptr
= L
"mouse-wheel-up";
478 case GDK_SCROLL_DOWN
:
479 ptr
= L
"mouse-wheel-down";
481 case GDK_SCROLL_LEFT
:
482 ptr
= L
"mouse-wheel-left";
484 case GDK_SCROLL_RIGHT
:
485 ptr
= L
"mouse-wheel-right";
490 mp_process_event(MPDM_S(ptr
));
498 static void value_changed(GtkAdjustment
* adj
, gpointer
* data
)
499 /* 'value_changed' handler (scrollbar) */
501 int i
= (int) adj
->value
;
506 /* get current y position */
508 txt
= mpdm_hget_s(doc
, L
"txt");
509 y
= mpdm_ival(mpdm_hget_s(txt
, L
"y"));
511 /* if it's different, set and redraw */
514 mpdm_hset_s(txt
, L
"vy", MPDM_I(i
));
520 static void draw_scrollbar(void)
521 /* updates the scrollbar */
523 GtkAdjustment
*adjustment
;
528 /* gets the active document */
529 if ((d
= mp_active()) == NULL
)
532 /* get the coordinates */
533 v
= mpdm_hget_s(d
, L
"txt");
534 pos
= mpdm_ival(mpdm_hget_s(v
, L
"vy"));
535 max
= mpdm_size(mpdm_hget_s(v
, L
"lines"));
537 v
= mpdm_hget_s(mp
, L
"window");
538 size
= mpdm_ival(mpdm_hget_s(v
, L
"ty"));
540 adjustment
= gtk_range_get_adjustment(GTK_RANGE(scrollbar
));
542 /* disconnect to avoid infinite loops */
543 g_signal_handlers_disconnect_by_func(G_OBJECT(adjustment
),
544 G_CALLBACK(value_changed
), NULL
);
546 adjustment
->step_increment
= (gfloat
) 1;
547 adjustment
->upper
= (gfloat
) max
;
548 adjustment
->page_size
= (gfloat
) size
;
549 adjustment
->page_increment
= (gfloat
) size
;
550 adjustment
->value
= (gfloat
) pos
;
552 gtk_range_set_adjustment(GTK_RANGE(scrollbar
), adjustment
);
554 gtk_adjustment_changed(adjustment
);
555 gtk_adjustment_value_changed(adjustment
);
558 g_signal_connect(G_OBJECT
559 (gtk_range_get_adjustment(GTK_RANGE(scrollbar
))),
560 "value_changed", G_CALLBACK(value_changed
), NULL
);
564 static void gtk_drv_paint(mpdm_t doc
, int optimize
)
565 /* GTK document draw function */
572 gtk_window_maximize(GTK_WINDOW(window
));
574 /* no gc? create it */
576 gc
= gdk_gc_new(area
->window
);
581 if ((d
= mp_draw(doc
, optimize
)) == NULL
)
588 gr
.width
= area
->allocation
.width
;
589 gr
.height
= font_height
;
591 for (n
= 0; n
< mpdm_size(d
); n
++) {
594 mpdm_t l
= mpdm_aget(d
, n
);
601 /* create the pango stuff */
602 pl
= gtk_widget_create_pango_layout(area
, NULL
);
603 pango_layout_set_font_description(pl
, font
);
604 pal
= pango_attr_list_new();
606 for (m
= u
= p
= 0; m
< mpdm_size(l
); m
++, u
= p
) {
612 /* get the attribute and the string */
613 attr
= mpdm_ival(mpdm_aget(l
, m
++));
616 /* convert the string to utf8 */
619 /* add to the full line */
620 str
= mpdm_poke(str
, &p
, ptr
, strlen(ptr
), 1);
624 /* create the background if it's
625 different from the default */
626 if (papers
[attr
].red
!= papers
[normal_attr
].red
||
627 papers
[attr
].green
!= papers
[normal_attr
].green
||
628 papers
[attr
].blue
!= papers
[normal_attr
].blue
) {
629 pa
= pango_attr_background_new(papers
[attr
].red
,
636 pango_attr_list_insert(pal
, pa
);
640 if (underlines
[attr
]) {
641 pa
= pango_attr_underline_new(TRUE
);
646 pango_attr_list_insert(pal
, pa
);
649 /* foreground color */
650 pa
= pango_attr_foreground_new(inks
[attr
].red
,
657 pango_attr_list_insert(pal
, pa
);
660 /* store the attributes */
661 pango_layout_set_attributes(pl
, pal
);
662 pango_attr_list_unref(pal
);
664 /* store and free the text */
665 pango_layout_set_text(pl
, str
, p
);
668 /* draw the background */
669 gdk_gc_set_foreground(gc
, &papers
[normal_attr
]);
670 gdk_draw_rectangle(pixmap
, gc
, TRUE
, 0, 0, gr
.width
, gr
.height
);
673 gtk_paint_layout(area
->style
, pixmap
,
674 GTK_STATE_NORMAL
, TRUE
, &gr
, area
, "", 2, 0, pl
);
676 /* dump the pixmap */
677 gdk_draw_pixmap(area
->window
, gc
, pixmap
,
678 0, 0, 0, n
* font_height
, gr
.width
, gr
.height
);
691 static void redraw(void)
693 if (mpdm_size(mpdm_hget_s(mp
, L
"docs")))
694 gtk_drv_paint(mp_active(), 0);
698 static gint
delete_event(GtkWidget
* w
, GdkEvent
* e
, gpointer data
)
699 /* 'delete_event' handler */
701 mp_process_event(MPDM_LS(L
"close-window"));
703 return mp_exit_requested
? FALSE
: TRUE
;
707 static void destroy(GtkWidget
* w
, gpointer data
)
708 /* 'destroy' handler */
714 static gint
key_release_event(GtkWidget
* widget
, GdkEventKey
* event
,
716 /* 'key_release_event' handler */
718 if (mp_keypress_throttle(0))
719 gtk_drv_paint(mp_active(), 0);
725 static gint
key_press_event(GtkWidget
* widget
, GdkEventKey
* event
,
727 /* 'key_press_event' handler */
731 gtk_im_context_filter_keypress(im
, event
);
733 /* set mp.shift_pressed */
734 if (event
->state
& (GDK_SHIFT_MASK
))
735 mpdm_hset_s(mp
, L
"shift_pressed", MPDM_I(1));
737 /* reserve alt for menu mnemonics */
738 /* if (GDK_MOD1_MASK & event->state)
741 if (event
->state
& (GDK_CONTROL_MASK
)) {
742 switch (event
->keyval
) {
744 ptr
= L
"ctrl-cursor-up";
747 ptr
= L
"ctrl-cursor-down";
750 ptr
= L
"ctrl-cursor-left";
753 ptr
= L
"ctrl-cursor-right";
756 ptr
= L
"ctrl-page-up";
759 ptr
= L
"ctrl-page-down";
771 ptr
= L
"ctrl-kp-plus";
773 case GDK_KP_Subtract
:
774 ptr
= L
"ctrl-kp-minus";
776 case GDK_KP_Multiply
:
777 ptr
= L
"ctrl-kp-multiply";
780 ptr
= L
"ctrl-kp-divide";
822 case GDK_Cyrillic_ve
:
828 case GDK_Cyrillic_tse
:
831 case GDK_Cyrillic_de
:
834 case GDK_Cyrillic_ie
:
837 case GDK_Cyrillic_ef
:
840 case GDK_Cyrillic_ghe
:
846 case GDK_Cyrillic_shorti
:
849 case GDK_Cyrillic_ka
:
852 case GDK_Cyrillic_el
:
855 case GDK_Cyrillic_em
:
858 case GDK_Cyrillic_en
:
864 case GDK_Cyrillic_pe
:
867 case GDK_Cyrillic_ya
:
870 case GDK_Cyrillic_er
:
873 case GDK_Cyrillic_es
:
876 case GDK_Cyrillic_te
:
879 case GDK_Cyrillic_softsign
:
882 case GDK_Cyrillic_yeru
:
885 case GDK_Cyrillic_ze
:
888 case GDK_Cyrillic_sha
:
894 case GDK_Cyrillic_shcha
:
897 case GDK_Cyrillic_che
:
903 char c
= event
->keyval
& 0xdf;
988 if (event
->state
& (GDK_MOD1_MASK
)) {
989 switch (event
->keyval
) {
991 ptr
= L
"alt-cursor-up";
994 ptr
= L
"alt-cursor-down";
997 ptr
= L
"alt-cursor-left";
1000 ptr
= L
"alt-cursor-right";
1003 ptr
= L
"alt-page-up";
1006 ptr
= L
"alt-page-down";
1018 ptr
= L
"alt-kp-plus";
1020 case GDK_KP_Subtract
:
1021 ptr
= L
"alt-kp-minus";
1023 case GDK_KP_Multiply
:
1024 ptr
= L
"alt-kp-multiply";
1027 ptr
= L
"alt-kp-divide";
1069 case GDK_Cyrillic_ve
:
1072 case GDK_Cyrillic_a
:
1075 case GDK_Cyrillic_tse
:
1078 case GDK_Cyrillic_de
:
1081 case GDK_Cyrillic_ie
:
1084 case GDK_Cyrillic_ef
:
1087 case GDK_Cyrillic_ghe
:
1090 case GDK_Cyrillic_i
:
1093 case GDK_Cyrillic_shorti
:
1096 case GDK_Cyrillic_ka
:
1099 case GDK_Cyrillic_el
:
1102 case GDK_Cyrillic_em
:
1105 case GDK_Cyrillic_en
:
1108 case GDK_Cyrillic_o
:
1111 case GDK_Cyrillic_pe
:
1114 case GDK_Cyrillic_ya
:
1117 case GDK_Cyrillic_er
:
1120 case GDK_Cyrillic_es
:
1123 case GDK_Cyrillic_te
:
1126 case GDK_Cyrillic_softsign
:
1129 case GDK_Cyrillic_yeru
:
1132 case GDK_Cyrillic_ze
:
1135 case GDK_Cyrillic_sha
:
1138 case GDK_Cyrillic_e
:
1141 case GDK_Cyrillic_shcha
:
1144 case GDK_Cyrillic_che
:
1150 char c
= event
->keyval
& 0xdf;
1235 switch (event
->keyval
) {
1240 ptr
= L
"cursor-down";
1243 ptr
= L
"cursor-left";
1246 ptr
= L
"cursor-right";
1266 case GDK_KP_Subtract
:
1269 case GDK_KP_Multiply
:
1270 ptr
= L
"kp-multiply";
1333 /* if there is a pending char in im_char, use it */
1334 if (ptr
== NULL
&& im_char
[0] != L
'\0')
1337 /* finally process */
1339 mp_process_event(MPDM_S(ptr
));
1341 /* delete the pending char */
1344 if (mp_exit_requested
)
1347 if (mp_keypress_throttle(1))
1348 gtk_drv_paint(mp_active(), 1);
1354 static gint
button_press_event(GtkWidget
* widget
, GdkEventButton
* event
,
1356 /* 'button_press_event' handler (mouse buttons) */
1359 wchar_t *ptr
= NULL
;
1363 /* mouse instant positioning */
1364 x
= ((int) event
->x
) / font_width
;
1365 y
= ((int) event
->y
) / font_height
;
1367 mpdm_hset_s(mp
, L
"mouse_x", MPDM_I(x
));
1368 mpdm_hset_s(mp
, L
"mouse_y", MPDM_I(y
));
1370 switch (event
->button
) {
1372 ptr
= L
"mouse-left-button";
1375 ptr
= L
"mouse-middle-button";
1378 ptr
= L
"mouse-right-button";
1381 ptr
= L
"mouse-wheel-up";
1384 ptr
= L
"mouse-wheel-down";
1389 mp_process_event(MPDM_S(ptr
));
1397 static gint
button_release_event(GtkWidget
* widget
,
1398 GdkEventButton
* event
, gpointer data
)
1399 /* 'button_release_event' handle (mouse buttons) */
1407 static gint
motion_notify_event(GtkWidget
* widget
, GdkEventMotion
* event
,
1409 /* 'motion_notify_event' handler (mouse movement) */
1417 /* mouse dragging */
1418 x
= ((int) event
->x
) / font_width
;
1419 y
= ((int) event
->y
) / font_height
;
1421 if (ox
!= x
&& oy
!= y
) {
1422 mpdm_hset_s(mp
, L
"mouse_to_x", MPDM_I(x
));
1423 mpdm_hset_s(mp
, L
"mouse_to_y", MPDM_I(y
));
1425 mp_process_event(MPDM_LS(L
"mouse-drag"));
1426 gtk_drv_paint(mp_active(), 1);
1434 static void drag_data_received(GtkWidget
* widget
, GdkDragContext
* dc
,
1435 gint x
, gint y
, GtkSelectionData
* data
,
1436 guint info
, guint time
)
1437 /* 'drag_data_received' handler */
1439 printf("drag_data_received (unsupported)\n");
1443 /** clipboard functions **/
1445 static void commit(GtkIMContext
* i
, char *str
, gpointer u
)
1446 /* 'commit' handler */
1450 wstr
= (wchar_t *) g_convert(str
, -1,
1451 "WCHAR_T", "UTF-8", NULL
, NULL
, NULL
);
1460 static void realize(GtkWidget
* widget
)
1461 /* 'realize' handler */
1463 im
= gtk_im_multicontext_new();
1464 g_signal_connect(im
, "commit", G_CALLBACK(commit
), NULL
);
1465 gtk_im_context_set_client_window(im
, widget
->window
);
1469 static gint
expose_event(GtkWidget
* widget
, GdkEventExpose
* event
)
1470 /* 'expose_event' handler */
1478 static gint
configure_event(GtkWidget
* widget
, GdkEventConfigure
* event
)
1479 /* 'configure_event' handler */
1481 static GdkEventConfigure o
;
1483 if (memcmp(&o
, event
, sizeof(o
)) == 0)
1486 memcpy(&o
, event
, sizeof(o
));
1488 update_window_size();
1495 static gint
selection_clear_event(GtkWidget
* widget
,
1496 GdkEventSelection
* event
, gpointer data
)
1497 /* 'selection_clear_event' handler */
1505 static void selection_get(GtkWidget
* widget
,
1506 GtkSelectionData
* sel
, guint info
, guint tm
)
1507 /* 'selection_get' handler */
1516 /* gets the clipboard and joins */
1517 d
= mpdm_hget_s(mp
, L
"clipboard");
1519 if (mpdm_size(d
) == 0)
1522 d
= mpdm_ref(mpdm_join_s(L
"\n", d
));
1524 /* convert to current locale */
1525 ptr
= (unsigned char *) mpdm_wcstombs(d
->data
, &s
);
1527 /* pastes into primary selection */
1528 gtk_selection_data_set(sel
, GDK_SELECTION_TYPE_STRING
, 8, ptr
,
1537 static void selection_received(GtkWidget
* widget
,
1538 GtkSelectionData
* sel
, gpointer data
)
1539 /* 'selection_received' handler */
1543 if (sel
->data
!= NULL
) {
1545 wchar_t *wptr
= utf8_to_wcs((char *) sel
->data
);
1549 /* split and set as the clipboard */
1550 mpdm_hset_s(mp
, L
"clipboard", mpdm_split_s(L
"\n", d
));
1551 mpdm_hset_s(mp
, L
"clipboard_vertical", MPDM_I(0));
1553 /* wait no more for the selection */
1554 wait_for_selection
= 0;
1557 wait_for_selection
= -1;
1561 static mpdm_t
gtk_drv_clip_to_sys(mpdm_t a
, mpdm_t ctxt
)
1562 /* driver-dependent mp to system clipboard */
1564 got_selection
= gtk_selection_owner_set(area
,
1565 GDK_SELECTION_PRIMARY
,
1572 static mpdm_t
gtk_drv_sys_to_clip(mpdm_t a
, mpdm_t ctxt
)
1573 /* driver-dependent system to mp clipboard */
1575 if (!got_selection
) {
1577 char *formats
[] = { "UTF8_STRING", "STRING", NULL
};
1579 for (n
= 0; formats
[n
] != NULL
; n
++) {
1581 /* triggers a selection capture */
1582 if (gtk_selection_convert(area
, GDK_SELECTION_PRIMARY
,
1583 gdk_atom_intern(formats
[n
], FALSE
),
1584 GDK_CURRENT_TIME
)) {
1586 /* processes the pending events
1587 (i.e., the 'selection_received' handler) */
1588 wait_for_selection
= 1;
1590 while (wait_for_selection
== 1)
1591 gtk_main_iteration();
1593 if (!wait_for_selection
)
1603 /** interface functions **/
1605 static void clicked_ok(GtkWidget
* widget
, gpointer data
)
1606 /* 'clicked_on' signal handler (for gtk_drv_form) */
1610 for (n
= 0; n
< mpdm_size(form_args
); n
++) {
1611 GtkWidget
*widget
= form_widgets
[n
];
1612 mpdm_t w
= mpdm_aget(form_args
, n
);
1613 wchar_t *wptr
= mpdm_string(mpdm_hget_s(w
, L
"type"));
1616 /* if there is already a value there, if was
1617 previously set from a callback */
1618 if (mpdm_aget(form_values
, n
) != NULL
)
1621 if (wcscmp(wptr
, L
"text") == 0 || wcscmp(wptr
, L
"password") == 0) {
1623 GtkWidget
*gw
= widget
;
1626 if (wcscmp(wptr
, L
"text") == 0)
1627 gw
= GTK_COMBO(widget
)->entry
;
1630 gtk_editable_get_chars(GTK_EDITABLE(gw
), 0, -1)) != NULL
1631 && (wptr
= utf8_to_wcs(ptr
)) != NULL
) {
1639 /* if it has history, fill it */
1640 if ((h
= mpdm_hget_s(w
, L
"history")) != NULL
&&
1641 v
!= NULL
&& mpdm_cmp_s(v
, L
"") != 0) {
1642 h
= mp_get_history(h
);
1644 if (mpdm_cmp(v
, mpdm_aget(h
, -1)) != 0)
1651 if (wcscmp(wptr
, L
"checkbox") == 0) {
1652 v
= MPDM_I(gtk_toggle_button_get_active
1653 (GTK_TOGGLE_BUTTON(widget
)));
1656 if (wcscmp(wptr
, L
"list") == 0) {
1657 GtkWidget
*list
= gtk_bin_get_child(GTK_BIN(widget
));
1658 GtkTreeSelection
*selection
=
1659 gtk_tree_view_get_selection(GTK_TREE_VIEW(list
));
1661 gtk_tree_selection_get_selected_rows(selection
, NULL
);
1662 GtkTreePath
*path
= selected
->data
;
1664 v
= MPDM_I(gtk_tree_path_get_indices(path
)[0]);
1665 gtk_tree_path_free(path
);
1666 g_list_free(selected
);
1670 mpdm_aset(form_values
, v
, n
);
1675 static gint
timer_callback(gpointer data
)
1677 mpdm_void(mpdm_exec(timer_func
, NULL
, NULL
));
1684 static void build_form_data(mpdm_t widget_list
)
1685 /* builds the necessary information for a list of widgets */
1687 mpdm_unref(form_args
);
1688 form_args
= mpdm_ref(widget_list
);
1690 mpdm_unref(form_values
);
1691 form_values
= widget_list
== NULL
? NULL
:
1692 mpdm_ref(MPDM_A(mpdm_size(form_args
)));
1694 /* resize the widget array */
1695 form_widgets
= (GtkWidget
**) realloc(form_widgets
,
1696 mpdm_size(form_args
) *
1697 sizeof(GtkWidget
*));
1701 /** dialog functions **/
1703 #define DIALOG_BUTTON(l,f) do { GtkWidget * btn; \
1704 ptr = localize(l); btn = gtk_button_new_with_label(ptr); \
1705 g_signal_connect_swapped(G_OBJECT(btn), "clicked", \
1706 G_CALLBACK(f), G_OBJECT(dlg)); \
1707 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), \
1708 btn, TRUE, TRUE, 0); \
1712 static mpdm_t
gtk_drv_alert(mpdm_t a
, mpdm_t ctxt
)
1713 /* alert driver function */
1718 build_form_data(NULL
);
1720 /* 1# arg: prompt */
1721 if ((ptr
= v_to_utf8(mpdm_aget(a
, 0))) == NULL
)
1724 dlg
= gtk_message_dialog_new(GTK_WINDOW(window
), GTK_DIALOG_MODAL
,
1725 GTK_MESSAGE_WARNING
, GTK_BUTTONS_OK
, ptr
);
1726 gtk_window_set_title(GTK_WINDOW(dlg
), "mp " VERSION
);
1729 gtk_dialog_run(GTK_DIALOG(dlg
));
1730 gtk_widget_destroy(dlg
);
1736 static mpdm_t
gtk_drv_confirm(mpdm_t a
, mpdm_t ctxt
)
1737 /* confirm driver function */
1743 build_form_data(NULL
);
1745 /* 1# arg: prompt */
1746 if ((ptr
= v_to_utf8(mpdm_aget(a
, 0))) == NULL
)
1749 dlg
= gtk_message_dialog_new(GTK_WINDOW(window
), GTK_DIALOG_MODAL
,
1750 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
,
1752 gtk_window_set_title(GTK_WINDOW(dlg
), "mp " VERSION
);
1755 gtk_dialog_add_button(GTK_DIALOG(dlg
), GTK_STOCK_YES
, 1);
1756 gtk_dialog_add_button(GTK_DIALOG(dlg
), GTK_STOCK_NO
, 2);
1757 gtk_dialog_add_button(GTK_DIALOG(dlg
), GTK_STOCK_CANCEL
, 0);
1759 response
= gtk_dialog_run(GTK_DIALOG(dlg
));
1760 gtk_widget_destroy(dlg
);
1762 if (response
== GTK_RESPONSE_DELETE_EVENT
)
1765 return MPDM_I(response
);
1769 static mpdm_t
gtk_drv_form(mpdm_t a
, mpdm_t ctxt
)
1770 /* 'form' driver function */
1774 GtkWidget
*content_area
;
1778 /* first argument: list of widgets */
1779 build_form_data(mpdm_aget(a
, 0));
1781 dlg
= gtk_dialog_new_with_buttons("mp " VERSION
, GTK_WINDOW(window
),
1783 GTK_DIALOG_NO_SEPARATOR
,
1785 GTK_RESPONSE_CANCEL
, GTK_STOCK_OK
,
1786 GTK_RESPONSE_OK
, NULL
);
1787 gtk_dialog_set_default_response(GTK_DIALOG(dlg
), GTK_RESPONSE_OK
);
1788 gtk_container_set_border_width(GTK_CONTAINER(dlg
), 5);
1790 content_area
= GTK_DIALOG(dlg
)->vbox
;
1791 gtk_box_set_spacing(GTK_BOX(content_area
), 2);
1793 table
= gtk_table_new(mpdm_size(a
), 2, FALSE
);
1794 gtk_container_set_border_width(GTK_CONTAINER(table
), 5);
1795 gtk_table_set_col_spacings(GTK_TABLE(table
), 12);
1796 gtk_table_set_row_spacings(GTK_TABLE(table
), 6);
1798 for (n
= 0; n
< mpdm_size(form_args
); n
++) {
1799 mpdm_t w
= mpdm_aget(form_args
, n
);
1800 GtkWidget
*widget
= NULL
;
1806 type
= mpdm_string(mpdm_hget_s(w
, L
"type"));
1808 if ((t
= mpdm_hget_s(w
, L
"label")) != NULL
) {
1811 if ((ptr
= v_to_utf8(mpdm_gettext(t
))) != NULL
) {
1812 label
= gtk_label_new(ptr
);
1813 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
1815 gtk_table_attach_defaults(GTK_TABLE(table
),
1816 label
, 0, wcscmp(type
,
1818 0 ? 2 : 1, n
, n
+ 1);
1826 t
= mpdm_hget_s(w
, L
"value");
1828 if (wcscmp(type
, L
"text") == 0) {
1829 GList
*combo_items
= NULL
;
1832 widget
= gtk_combo_new();
1833 gtk_widget_set_size_request(widget
, 300, -1);
1834 gtk_combo_set_use_arrows_always(GTK_COMBO(widget
), TRUE
);
1835 gtk_combo_set_case_sensitive(GTK_COMBO(widget
), TRUE
);
1836 gtk_entry_set_activates_default(GTK_ENTRY
1837 (GTK_COMBO(widget
)->entry
),
1840 if ((h
= mpdm_hget_s(w
, L
"history")) != NULL
) {
1843 /* has history; fill it */
1844 h
= mp_get_history(h
);
1846 for (i
= 0; i
< mpdm_size(h
); i
++) {
1847 ptr
= v_to_utf8(mpdm_aget(h
, i
));
1849 combo_items
= g_list_prepend(combo_items
, ptr
);
1856 combo_items
= g_list_prepend(combo_items
, ptr
);
1859 gtk_combo_set_popdown_strings(GTK_COMBO(widget
), combo_items
);
1860 g_list_free(combo_items
);
1863 if (wcscmp(type
, L
"password") == 0) {
1864 widget
= gtk_entry_new();
1865 gtk_widget_set_size_request(widget
, 300, -1);
1866 gtk_entry_set_visibility(GTK_ENTRY(widget
), FALSE
);
1869 if (wcscmp(type
, L
"checkbox") == 0) {
1870 widget
= gtk_check_button_new();
1872 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget
),
1873 mpdm_ival(t
) ? TRUE
: FALSE
);
1876 if (wcscmp(type
, L
"list") == 0) {
1878 GtkListStore
*list_store
;
1879 GtkCellRenderer
*renderer
;
1880 GtkTreeViewColumn
*column
;
1885 if ((i
= 450 / mpdm_size(form_args
)) < 100)
1888 widget
= gtk_scrolled_window_new(NULL
, NULL
);
1889 gtk_widget_set_size_request(widget
, 500, i
);
1890 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget
),
1892 GTK_POLICY_AUTOMATIC
);
1893 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW
1894 (widget
), GTK_SHADOW_IN
);
1896 list_store
= gtk_list_store_new(1, G_TYPE_STRING
);
1898 gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store
));
1899 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list
), FALSE
);
1900 renderer
= gtk_cell_renderer_text_new();
1901 column
= gtk_tree_view_column_new_with_attributes("", renderer
,
1904 gtk_tree_view_append_column(GTK_TREE_VIEW(list
), column
);
1905 gtk_container_add(GTK_CONTAINER(widget
), list
);
1907 l
= mpdm_hget_s(w
, L
"list");
1909 for (i
= 0; i
< mpdm_size(l
); i
++) {
1910 if ((ptr
= v_to_utf8(mpdm_aget(l
, i
))) != NULL
) {
1912 gtk_list_store_append(list_store
, &iter
);
1913 gtk_list_store_set(list_store
, &iter
, 0, ptr
, -1);
1918 /* initial position */
1921 path
= gtk_tree_path_new_from_indices(i
, -1);
1922 gtk_tree_view_set_cursor(GTK_TREE_VIEW(list
), path
, NULL
,
1924 gtk_tree_path_free(path
);
1926 g_signal_connect_swapped(G_OBJECT(list
), "row-activated",
1928 (gtk_window_activate_default
), dlg
);
1931 if (widget
!= NULL
) {
1932 form_widgets
[n
] = widget
;
1933 gtk_table_attach_defaults(GTK_TABLE(table
),
1934 widget
, col
, 2, n
, n
+ 1);
1938 gtk_widget_show_all(table
);
1940 gtk_box_pack_start(GTK_BOX(content_area
), table
, TRUE
, TRUE
, 0);
1942 if (gtk_dialog_run(GTK_DIALOG(dlg
)) == GTK_RESPONSE_OK
) {
1943 clicked_ok(NULL
, NULL
);
1946 gtk_widget_destroy(dlg
);
1952 static mpdm_t
run_filechooser(mpdm_t a
, gboolean save
)
1953 /* openfile driver function */
1960 /* 1# arg: prompt */
1961 if ((ptr
= v_to_utf8(mpdm_aget(a
, 0))) == NULL
)
1965 dlg
= gtk_file_chooser_dialog_new(ptr
, GTK_WINDOW(window
),
1966 GTK_FILE_CHOOSER_ACTION_OPEN
,
1968 GTK_RESPONSE_CANCEL
,
1969 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
1973 dlg
= gtk_file_chooser_dialog_new(ptr
, GTK_WINDOW(window
),
1974 GTK_FILE_CHOOSER_ACTION_SAVE
,
1976 GTK_STOCK_CANCEL
, GTK_STOCK_OK
,
1977 GTK_RESPONSE_OK
, NULL
);
1978 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER
1983 build_form_data(NULL
);
1985 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg
), TRUE
);
1986 response
= gtk_dialog_run(GTK_DIALOG(dlg
));
1988 if (response
== GTK_RESPONSE_OK
) {
1993 filename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg
));
1994 utf8name
= g_filename_to_utf8(filename
, -1, NULL
, NULL
, NULL
);
1996 wfilename
= utf8_to_wcs(utf8name
);
1998 ret
= MPDM_S(wfilename
);
2001 gtk_widget_destroy(dlg
);
2007 static mpdm_t
gtk_drv_openfile(mpdm_t a
, mpdm_t ctxt
)
2008 /* openfile driver function */
2010 return run_filechooser(a
, FALSE
);
2014 static mpdm_t
gtk_drv_savefile(mpdm_t a
, mpdm_t ctxt
)
2015 /* savefile driver function */
2017 return run_filechooser(a
, TRUE
);
2021 static mpdm_t
gtk_drv_update_ui(mpdm_t a
, mpdm_t ctxt
)
2033 static mpdm_t
gtk_drv_timer(mpdm_t a
, mpdm_t ctxt
)
2035 static guint prev
= 0;
2036 int msecs
= mpdm_ival(mpdm_aget(a
, 0));
2037 mpdm_t func
= mpdm_aget(a
, 1);
2039 /* previously defined one? remove */
2040 if (timer_func
!= NULL
)
2041 gtk_timeout_remove(prev
);
2043 /* if msecs and func are set, program timer */
2044 if (msecs
> 0 && func
!= NULL
)
2045 prev
= gtk_timeout_add(msecs
, timer_callback
, NULL
);
2048 mpdm_unref(timer_func
);
2055 static mpdm_t
gtk_drv_busy(mpdm_t a
, mpdm_t ctxt
)
2057 int onoff
= mpdm_ival(mpdm_aget(a
, 0));
2059 gdk_window_set_cursor(window
->window
,
2060 gdk_cursor_new(onoff
? GDK_WATCH
:
2063 while (gtk_events_pending())
2064 gtk_main_iteration();
2070 static mpdm_t
gtk_drv_main_loop(mpdm_t a
, mpdm_t ctxt
)
2073 if (!mp_exit_requested
) {
2074 gtk_drv_paint(mp_active(), 0);
2083 static mpdm_t
gtk_drv_shutdown(mpdm_t a
, mpdm_t ctxt
)
2088 if ((v
= mpdm_hget_s(mp
, L
"exit_message")) != NULL
) {
2089 mpdm_write_wcs(stdout
, mpdm_string(v
));
2097 static void register_functions(void)
2101 drv
= mpdm_hget_s(mp
, L
"drv");
2102 mpdm_hset_s(drv
, L
"main_loop", MPDM_X(gtk_drv_main_loop
));
2103 mpdm_hset_s(drv
, L
"shutdown", MPDM_X(gtk_drv_shutdown
));
2104 mpdm_hset_s(drv
, L
"clip_to_sys", MPDM_X(gtk_drv_clip_to_sys
));
2105 mpdm_hset_s(drv
, L
"sys_to_clip", MPDM_X(gtk_drv_sys_to_clip
));
2106 mpdm_hset_s(drv
, L
"update_ui", MPDM_X(gtk_drv_update_ui
));
2107 mpdm_hset_s(drv
, L
"timer", MPDM_X(gtk_drv_timer
));
2108 mpdm_hset_s(drv
, L
"busy", MPDM_X(gtk_drv_busy
));
2109 mpdm_hset_s(drv
, L
"alert", MPDM_X(gtk_drv_alert
));
2110 mpdm_hset_s(drv
, L
"confirm", MPDM_X(gtk_drv_confirm
));
2111 mpdm_hset_s(drv
, L
"openfile", MPDM_X(gtk_drv_openfile
));
2112 mpdm_hset_s(drv
, L
"savefile", MPDM_X(gtk_drv_savefile
));
2113 mpdm_hset_s(drv
, L
"form", MPDM_X(gtk_drv_form
));
2117 static mpdm_t
gtk_drv_startup(mpdm_t a
, mpdm_t ctxt
)
2118 /* driver initialization */
2127 GtkTargetEntry targets
[] = {
2128 {"text/plain", 0, 0},
2129 {"text/uri-list", 0, 1}
2132 register_functions();
2134 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
2136 gtk_window_set_title(GTK_WINDOW(window
), "mp " VERSION
);
2138 /* get real screen and pick a usable size for the main area */
2139 screen
= gtk_window_get_screen(GTK_WINDOW(window
));
2140 w
= (gdk_screen_get_width(screen
) * 3) / 4;
2141 h
= (gdk_screen_get_height(screen
) * 2) / 3;
2143 g_signal_connect(G_OBJECT(window
), "delete_event",
2144 G_CALLBACK(delete_event
), NULL
);
2146 g_signal_connect(G_OBJECT(window
), "destroy",
2147 G_CALLBACK(destroy
), NULL
);
2150 file_tabs
= gtk_notebook_new();
2151 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(file_tabs
), GTK_POS_TOP
);
2152 GTK_WIDGET_UNSET_FLAGS(file_tabs
, GTK_CAN_FOCUS
);
2153 gtk_notebook_set_scrollable(GTK_NOTEBOOK(file_tabs
), 1);
2155 vbox
= gtk_vbox_new(FALSE
, 2);
2156 gtk_container_add(GTK_CONTAINER(window
), vbox
);
2160 hbox
= gtk_hbox_new(FALSE
, 0);
2161 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
2162 gtk_box_pack_start(GTK_BOX(hbox
), menu_bar
, FALSE
, FALSE
, 0);
2163 gtk_box_pack_start(GTK_BOX(hbox
), file_tabs
, TRUE
, TRUE
, 0);
2165 gtk_notebook_popup_enable(GTK_NOTEBOOK(file_tabs
));
2167 /* horizontal box holding the text and the scrollbar */
2168 hbox
= gtk_hbox_new(FALSE
, 2);
2169 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, TRUE
, TRUE
, 0);
2171 /* the Minimum Profit area */
2172 area
= gtk_drawing_area_new();
2173 gtk_box_pack_start(GTK_BOX(hbox
), area
, TRUE
, TRUE
, 0);
2174 gtk_widget_set_size_request(GTK_WIDGET(area
), w
, h
);
2175 gtk_widget_set_events(GTK_WIDGET(area
), GDK_BUTTON_PRESS_MASK
|
2176 GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK
2177 | GDK_LEAVE_NOTIFY_MASK
);
2179 gtk_widget_set_double_buffered(area
, FALSE
);
2181 g_signal_connect(G_OBJECT(area
), "configure_event",
2182 G_CALLBACK(configure_event
), NULL
);
2184 g_signal_connect(G_OBJECT(area
), "expose_event",
2185 G_CALLBACK(expose_event
), NULL
);
2187 g_signal_connect(G_OBJECT(area
), "realize", G_CALLBACK(realize
), NULL
);
2189 g_signal_connect(G_OBJECT(window
), "key_press_event",
2190 G_CALLBACK(key_press_event
), NULL
);
2192 g_signal_connect(G_OBJECT(window
), "key_release_event",
2193 G_CALLBACK(key_release_event
), NULL
);
2195 g_signal_connect(G_OBJECT(area
), "button_press_event",
2196 G_CALLBACK(button_press_event
), NULL
);
2198 g_signal_connect(G_OBJECT(area
), "button_release_event",
2199 G_CALLBACK(button_release_event
), NULL
);
2201 g_signal_connect(G_OBJECT(area
), "motion_notify_event",
2202 G_CALLBACK(motion_notify_event
), NULL
);
2204 g_signal_connect(G_OBJECT(area
), "selection_clear_event",
2205 G_CALLBACK(selection_clear_event
), NULL
);
2207 g_signal_connect(G_OBJECT(area
), "selection_get",
2208 G_CALLBACK(selection_get
), NULL
);
2210 g_signal_connect(G_OBJECT(area
), "selection_received",
2211 G_CALLBACK(selection_received
), NULL
);
2213 g_signal_connect(G_OBJECT(area
), "scroll_event",
2214 G_CALLBACK(scroll_event
), NULL
);
2216 gtk_drag_dest_set(area
, GTK_DEST_DEFAULT_ALL
, targets
,
2217 sizeof(targets
) / sizeof(GtkTargetEntry
),
2219 g_signal_connect(G_OBJECT(area
), "drag_data_received",
2220 G_CALLBACK(drag_data_received
), NULL
);
2222 gtk_selection_add_target(area
, GDK_SELECTION_PRIMARY
,
2223 GDK_SELECTION_TYPE_STRING
, 1);
2225 g_signal_connect(G_OBJECT(file_tabs
), "switch_page",
2226 G_CALLBACK(switch_page
), NULL
);
2229 scrollbar
= gtk_vscrollbar_new(NULL
);
2230 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, FALSE
, 0);
2232 g_signal_connect(G_OBJECT
2233 (gtk_range_get_adjustment(GTK_RANGE(scrollbar
))),
2234 "value_changed", G_CALLBACK(value_changed
), NULL
);
2236 /* the status bar */
2237 status
= gtk_label_new("mp " VERSION
);
2238 gtk_box_pack_start(GTK_BOX(vbox
), status
, FALSE
, FALSE
, 0);
2239 gtk_misc_set_alignment(GTK_MISC(status
), 0, 0.5);
2240 gtk_label_set_justify(GTK_LABEL(status
), GTK_JUSTIFY_LEFT
);
2242 gtk_widget_show_all(window
);
2244 /* set application icon */
2245 pixmap
= gdk_pixmap_create_from_xpm_d(window
->window
,
2246 &mask
, NULL
, mp_xpm
);
2247 gdk_window_set_icon(window
->window
, NULL
, pixmap
, mask
);
2251 if ((v
= mpdm_hget_s(mp
, L
"config")) != NULL
&&
2252 mpdm_ival(mpdm_hget_s(v
, L
"maximize")) > 0)
2259 int gtk_drv_detect(int *argc
, char ***argv
)
2264 for (n
= 0; n
< *argc
; n
++) {
2265 if (strcmp(argv
[0][n
], "-txt") == 0 ||
2266 strcmp(argv
[0][n
], "-h") == 0)
2270 if (!gtk_init_check(argc
, argv
))
2273 drv
= mpdm_hget_s(mp
, L
"drv");
2274 mpdm_hset_s(drv
, L
"id", MPDM_LS(L
"gtk"));
2275 mpdm_hset_s(drv
, L
"startup", MPDM_X(gtk_drv_startup
));
2280 #endif /* CONFOPT_GTK */