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";
1327 case GDK_ISO_Left_Tab
:
1336 /* if there is a pending char in im_char, use it */
1337 if (ptr
== NULL
&& im_char
[0] != L
'\0')
1340 /* finally process */
1342 mp_process_event(MPDM_S(ptr
));
1344 /* delete the pending char */
1347 if (mp_exit_requested
)
1350 if (mp_keypress_throttle(1))
1351 gtk_drv_paint(mp_active(), 1);
1357 static gint
button_press_event(GtkWidget
* widget
, GdkEventButton
* event
,
1359 /* 'button_press_event' handler (mouse buttons) */
1362 wchar_t *ptr
= NULL
;
1366 /* mouse instant positioning */
1367 x
= ((int) event
->x
) / font_width
;
1368 y
= ((int) event
->y
) / font_height
;
1370 mpdm_hset_s(mp
, L
"mouse_x", MPDM_I(x
));
1371 mpdm_hset_s(mp
, L
"mouse_y", MPDM_I(y
));
1373 switch (event
->button
) {
1375 ptr
= L
"mouse-left-button";
1378 ptr
= L
"mouse-middle-button";
1381 ptr
= L
"mouse-right-button";
1384 ptr
= L
"mouse-wheel-up";
1387 ptr
= L
"mouse-wheel-down";
1392 mp_process_event(MPDM_S(ptr
));
1400 static gint
button_release_event(GtkWidget
* widget
,
1401 GdkEventButton
* event
, gpointer data
)
1402 /* 'button_release_event' handle (mouse buttons) */
1410 static gint
motion_notify_event(GtkWidget
* widget
, GdkEventMotion
* event
,
1412 /* 'motion_notify_event' handler (mouse movement) */
1420 /* mouse dragging */
1421 x
= ((int) event
->x
) / font_width
;
1422 y
= ((int) event
->y
) / font_height
;
1424 if (ox
!= x
&& oy
!= y
) {
1425 mpdm_hset_s(mp
, L
"mouse_to_x", MPDM_I(x
));
1426 mpdm_hset_s(mp
, L
"mouse_to_y", MPDM_I(y
));
1428 mp_process_event(MPDM_LS(L
"mouse-drag"));
1429 gtk_drv_paint(mp_active(), 1);
1437 static void drag_data_received(GtkWidget
* widget
, GdkDragContext
* dc
,
1438 gint x
, gint y
, GtkSelectionData
* data
,
1439 guint info
, guint time
)
1440 /* 'drag_data_received' handler */
1442 printf("drag_data_received (unsupported)\n");
1446 /** clipboard functions **/
1448 static void commit(GtkIMContext
* i
, char *str
, gpointer u
)
1449 /* 'commit' handler */
1453 wstr
= (wchar_t *) g_convert(str
, -1,
1454 "WCHAR_T", "UTF-8", NULL
, NULL
, NULL
);
1463 static void realize(GtkWidget
* widget
)
1464 /* 'realize' handler */
1466 im
= gtk_im_multicontext_new();
1467 g_signal_connect(im
, "commit", G_CALLBACK(commit
), NULL
);
1468 gtk_im_context_set_client_window(im
, widget
->window
);
1472 static gint
expose_event(GtkWidget
* widget
, GdkEventExpose
* event
)
1473 /* 'expose_event' handler */
1481 static gint
configure_event(GtkWidget
* widget
, GdkEventConfigure
* event
)
1482 /* 'configure_event' handler */
1484 static GdkEventConfigure o
;
1486 if (memcmp(&o
, event
, sizeof(o
)) == 0)
1489 memcpy(&o
, event
, sizeof(o
));
1491 update_window_size();
1498 static gint
selection_clear_event(GtkWidget
* widget
,
1499 GdkEventSelection
* event
, gpointer data
)
1500 /* 'selection_clear_event' handler */
1508 static void selection_get(GtkWidget
* widget
,
1509 GtkSelectionData
* sel
, guint info
, guint tm
)
1510 /* 'selection_get' handler */
1519 /* gets the clipboard and joins */
1520 d
= mpdm_hget_s(mp
, L
"clipboard");
1522 if (mpdm_size(d
) == 0)
1525 d
= mpdm_ref(mpdm_join_s(d
, L
"\n"));
1527 /* convert to current locale */
1528 ptr
= (unsigned char *) mpdm_wcstombs(d
->data
, &s
);
1530 /* pastes into primary selection */
1531 gtk_selection_data_set(sel
, GDK_SELECTION_TYPE_STRING
, 8, ptr
,
1540 static void selection_received(GtkWidget
* widget
,
1541 GtkSelectionData
* sel
, gpointer data
)
1542 /* 'selection_received' handler */
1546 if (sel
->data
!= NULL
) {
1548 wchar_t *wptr
= utf8_to_wcs((char *) sel
->data
);
1552 /* split and set as the clipboard */
1553 mpdm_hset_s(mp
, L
"clipboard", mpdm_split_s(d
, L
"\n"));
1554 mpdm_hset_s(mp
, L
"clipboard_vertical", MPDM_I(0));
1556 /* wait no more for the selection */
1557 wait_for_selection
= 0;
1560 wait_for_selection
= -1;
1564 static mpdm_t
gtk_drv_clip_to_sys(mpdm_t a
, mpdm_t ctxt
)
1565 /* driver-dependent mp to system clipboard */
1567 got_selection
= gtk_selection_owner_set(area
,
1568 GDK_SELECTION_PRIMARY
,
1575 static mpdm_t
gtk_drv_sys_to_clip(mpdm_t a
, mpdm_t ctxt
)
1576 /* driver-dependent system to mp clipboard */
1578 if (!got_selection
) {
1580 char *formats
[] = { "UTF8_STRING", "STRING", NULL
};
1582 for (n
= 0; formats
[n
] != NULL
; n
++) {
1584 /* triggers a selection capture */
1585 if (gtk_selection_convert(area
, GDK_SELECTION_PRIMARY
,
1586 gdk_atom_intern(formats
[n
], FALSE
),
1587 GDK_CURRENT_TIME
)) {
1589 /* processes the pending events
1590 (i.e., the 'selection_received' handler) */
1591 wait_for_selection
= 1;
1593 while (wait_for_selection
== 1)
1594 gtk_main_iteration();
1596 if (!wait_for_selection
)
1606 /** interface functions **/
1608 static void clicked_ok(GtkWidget
* widget
, gpointer data
)
1609 /* 'clicked_on' signal handler (for gtk_drv_form) */
1613 for (n
= 0; n
< mpdm_size(form_args
); n
++) {
1614 GtkWidget
*widget
= form_widgets
[n
];
1615 mpdm_t w
= mpdm_aget(form_args
, n
);
1616 wchar_t *wptr
= mpdm_string(mpdm_hget_s(w
, L
"type"));
1619 /* if there is already a value there, if was
1620 previously set from a callback */
1621 if (mpdm_aget(form_values
, n
) != NULL
)
1624 if (wcscmp(wptr
, L
"text") == 0 || wcscmp(wptr
, L
"password") == 0) {
1626 GtkWidget
*gw
= widget
;
1629 if (wcscmp(wptr
, L
"text") == 0)
1630 gw
= GTK_COMBO(widget
)->entry
;
1633 gtk_editable_get_chars(GTK_EDITABLE(gw
), 0, -1)) != NULL
1634 && (wptr
= utf8_to_wcs(ptr
)) != NULL
) {
1642 /* if it has history, fill it */
1643 if ((h
= mpdm_hget_s(w
, L
"history")) != NULL
&&
1644 v
!= NULL
&& mpdm_cmp_s(v
, L
"") != 0) {
1645 h
= mp_get_history(h
);
1647 if (mpdm_cmp(v
, mpdm_aget(h
, -1)) != 0)
1654 if (wcscmp(wptr
, L
"checkbox") == 0) {
1655 v
= MPDM_I(gtk_toggle_button_get_active
1656 (GTK_TOGGLE_BUTTON(widget
)));
1659 if (wcscmp(wptr
, L
"list") == 0) {
1660 GtkWidget
*list
= gtk_bin_get_child(GTK_BIN(widget
));
1661 GtkTreeSelection
*selection
=
1662 gtk_tree_view_get_selection(GTK_TREE_VIEW(list
));
1664 gtk_tree_selection_get_selected_rows(selection
, NULL
);
1665 GtkTreePath
*path
= selected
->data
;
1667 v
= MPDM_I(gtk_tree_path_get_indices(path
)[0]);
1668 gtk_tree_path_free(path
);
1669 g_list_free(selected
);
1673 mpdm_aset(form_values
, v
, n
);
1678 static gint
timer_callback(gpointer data
)
1680 mpdm_void(mpdm_exec(timer_func
, NULL
, NULL
));
1687 static void build_form_data(mpdm_t widget_list
)
1688 /* builds the necessary information for a list of widgets */
1690 mpdm_unref(form_args
);
1691 form_args
= mpdm_ref(widget_list
);
1693 mpdm_unref(form_values
);
1694 form_values
= widget_list
== NULL
? NULL
:
1695 mpdm_ref(MPDM_A(mpdm_size(form_args
)));
1697 /* resize the widget array */
1698 form_widgets
= (GtkWidget
**) realloc(form_widgets
,
1699 mpdm_size(form_args
) *
1700 sizeof(GtkWidget
*));
1704 /** dialog functions **/
1706 #define DIALOG_BUTTON(l,f) do { GtkWidget * btn; \
1707 ptr = localize(l); btn = gtk_button_new_with_label(ptr); \
1708 g_signal_connect_swapped(G_OBJECT(btn), "clicked", \
1709 G_CALLBACK(f), G_OBJECT(dlg)); \
1710 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), \
1711 btn, TRUE, TRUE, 0); \
1715 static mpdm_t
gtk_drv_alert(mpdm_t a
, mpdm_t ctxt
)
1716 /* alert driver function */
1721 build_form_data(NULL
);
1723 /* 1# arg: prompt */
1724 if ((ptr
= v_to_utf8(mpdm_aget(a
, 0))) == NULL
)
1727 dlg
= gtk_message_dialog_new(GTK_WINDOW(window
), GTK_DIALOG_MODAL
,
1728 GTK_MESSAGE_WARNING
, GTK_BUTTONS_OK
, ptr
);
1729 gtk_window_set_title(GTK_WINDOW(dlg
), "mp " VERSION
);
1732 gtk_dialog_run(GTK_DIALOG(dlg
));
1733 gtk_widget_destroy(dlg
);
1739 static mpdm_t
gtk_drv_confirm(mpdm_t a
, mpdm_t ctxt
)
1740 /* confirm driver function */
1746 build_form_data(NULL
);
1748 /* 1# arg: prompt */
1749 if ((ptr
= v_to_utf8(mpdm_aget(a
, 0))) == NULL
)
1752 dlg
= gtk_message_dialog_new(GTK_WINDOW(window
), GTK_DIALOG_MODAL
,
1753 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
,
1755 gtk_window_set_title(GTK_WINDOW(dlg
), "mp " VERSION
);
1758 gtk_dialog_add_button(GTK_DIALOG(dlg
), GTK_STOCK_YES
, 1);
1759 gtk_dialog_add_button(GTK_DIALOG(dlg
), GTK_STOCK_NO
, 2);
1760 gtk_dialog_add_button(GTK_DIALOG(dlg
), GTK_STOCK_CANCEL
, 0);
1762 response
= gtk_dialog_run(GTK_DIALOG(dlg
));
1763 gtk_widget_destroy(dlg
);
1765 if (response
== GTK_RESPONSE_DELETE_EVENT
)
1768 return MPDM_I(response
);
1772 static mpdm_t
gtk_drv_form(mpdm_t a
, mpdm_t ctxt
)
1773 /* 'form' driver function */
1777 GtkWidget
*content_area
;
1781 /* first argument: list of widgets */
1782 build_form_data(mpdm_aget(a
, 0));
1784 dlg
= gtk_dialog_new_with_buttons("mp " VERSION
, GTK_WINDOW(window
),
1786 GTK_DIALOG_NO_SEPARATOR
,
1788 GTK_RESPONSE_CANCEL
, GTK_STOCK_OK
,
1789 GTK_RESPONSE_OK
, NULL
);
1790 gtk_dialog_set_default_response(GTK_DIALOG(dlg
), GTK_RESPONSE_OK
);
1791 gtk_container_set_border_width(GTK_CONTAINER(dlg
), 5);
1793 content_area
= GTK_DIALOG(dlg
)->vbox
;
1794 gtk_box_set_spacing(GTK_BOX(content_area
), 2);
1796 table
= gtk_table_new(mpdm_size(a
), 2, FALSE
);
1797 gtk_container_set_border_width(GTK_CONTAINER(table
), 5);
1798 gtk_table_set_col_spacings(GTK_TABLE(table
), 12);
1799 gtk_table_set_row_spacings(GTK_TABLE(table
), 6);
1801 for (n
= 0; n
< mpdm_size(form_args
); n
++) {
1802 mpdm_t w
= mpdm_aget(form_args
, n
);
1803 GtkWidget
*widget
= NULL
;
1809 type
= mpdm_string(mpdm_hget_s(w
, L
"type"));
1811 if ((t
= mpdm_hget_s(w
, L
"label")) != NULL
) {
1814 if ((ptr
= v_to_utf8(mpdm_gettext(t
))) != NULL
) {
1815 label
= gtk_label_new(ptr
);
1816 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
1818 gtk_table_attach_defaults(GTK_TABLE(table
),
1819 label
, 0, wcscmp(type
,
1821 0 ? 2 : 1, n
, n
+ 1);
1829 t
= mpdm_hget_s(w
, L
"value");
1831 if (wcscmp(type
, L
"text") == 0) {
1832 GList
*combo_items
= NULL
;
1835 widget
= gtk_combo_new();
1836 gtk_widget_set_size_request(widget
, 300, -1);
1837 gtk_combo_set_use_arrows_always(GTK_COMBO(widget
), TRUE
);
1838 gtk_combo_set_case_sensitive(GTK_COMBO(widget
), TRUE
);
1839 gtk_entry_set_activates_default(GTK_ENTRY
1840 (GTK_COMBO(widget
)->entry
),
1843 if ((h
= mpdm_hget_s(w
, L
"history")) != NULL
) {
1846 /* has history; fill it */
1847 h
= mp_get_history(h
);
1849 for (i
= 0; i
< mpdm_size(h
); i
++) {
1850 ptr
= v_to_utf8(mpdm_aget(h
, i
));
1852 combo_items
= g_list_prepend(combo_items
, ptr
);
1859 combo_items
= g_list_prepend(combo_items
, ptr
);
1862 gtk_combo_set_popdown_strings(GTK_COMBO(widget
), combo_items
);
1863 g_list_free(combo_items
);
1866 if (wcscmp(type
, L
"password") == 0) {
1867 widget
= gtk_entry_new();
1868 gtk_widget_set_size_request(widget
, 300, -1);
1869 gtk_entry_set_visibility(GTK_ENTRY(widget
), FALSE
);
1872 if (wcscmp(type
, L
"checkbox") == 0) {
1873 widget
= gtk_check_button_new();
1875 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget
),
1876 mpdm_ival(t
) ? TRUE
: FALSE
);
1879 if (wcscmp(type
, L
"list") == 0) {
1881 GtkListStore
*list_store
;
1882 GtkCellRenderer
*renderer
;
1883 GtkTreeViewColumn
*column
;
1888 if ((i
= 450 / mpdm_size(form_args
)) < 100)
1891 widget
= gtk_scrolled_window_new(NULL
, NULL
);
1892 gtk_widget_set_size_request(widget
, 500, i
);
1893 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget
),
1895 GTK_POLICY_AUTOMATIC
);
1896 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW
1897 (widget
), GTK_SHADOW_IN
);
1899 list_store
= gtk_list_store_new(1, G_TYPE_STRING
);
1901 gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store
));
1902 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list
), FALSE
);
1903 renderer
= gtk_cell_renderer_text_new();
1904 column
= gtk_tree_view_column_new_with_attributes("", renderer
,
1907 gtk_tree_view_append_column(GTK_TREE_VIEW(list
), column
);
1908 gtk_container_add(GTK_CONTAINER(widget
), list
);
1910 l
= mpdm_hget_s(w
, L
"list");
1912 for (i
= 0; i
< mpdm_size(l
); i
++) {
1913 if ((ptr
= v_to_utf8(mpdm_aget(l
, i
))) != NULL
) {
1915 gtk_list_store_append(list_store
, &iter
);
1916 gtk_list_store_set(list_store
, &iter
, 0, ptr
, -1);
1921 /* initial position */
1924 path
= gtk_tree_path_new_from_indices(i
, -1);
1925 gtk_tree_view_set_cursor(GTK_TREE_VIEW(list
), path
, NULL
,
1927 gtk_tree_path_free(path
);
1929 g_signal_connect_swapped(G_OBJECT(list
), "row-activated",
1931 (gtk_window_activate_default
), dlg
);
1934 if (widget
!= NULL
) {
1935 form_widgets
[n
] = widget
;
1936 gtk_table_attach_defaults(GTK_TABLE(table
),
1937 widget
, col
, 2, n
, n
+ 1);
1941 gtk_widget_show_all(table
);
1943 gtk_box_pack_start(GTK_BOX(content_area
), table
, TRUE
, TRUE
, 0);
1945 if (gtk_dialog_run(GTK_DIALOG(dlg
)) == GTK_RESPONSE_OK
) {
1946 clicked_ok(NULL
, NULL
);
1949 gtk_widget_destroy(dlg
);
1955 static mpdm_t
run_filechooser(mpdm_t a
, gboolean save
)
1956 /* openfile driver function */
1963 /* 1# arg: prompt */
1964 if ((ptr
= v_to_utf8(mpdm_aget(a
, 0))) == NULL
)
1968 dlg
= gtk_file_chooser_dialog_new(ptr
, GTK_WINDOW(window
),
1969 GTK_FILE_CHOOSER_ACTION_OPEN
,
1971 GTK_RESPONSE_CANCEL
,
1972 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
1976 dlg
= gtk_file_chooser_dialog_new(ptr
, GTK_WINDOW(window
),
1977 GTK_FILE_CHOOSER_ACTION_SAVE
,
1979 GTK_STOCK_CANCEL
, GTK_STOCK_OK
,
1980 GTK_RESPONSE_OK
, NULL
);
1981 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER
1986 build_form_data(NULL
);
1988 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg
), TRUE
);
1989 response
= gtk_dialog_run(GTK_DIALOG(dlg
));
1991 if (response
== GTK_RESPONSE_OK
) {
1996 filename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg
));
1997 utf8name
= g_filename_to_utf8(filename
, -1, NULL
, NULL
, NULL
);
1999 wfilename
= utf8_to_wcs(utf8name
);
2001 ret
= MPDM_S(wfilename
);
2004 gtk_widget_destroy(dlg
);
2010 static mpdm_t
gtk_drv_openfile(mpdm_t a
, mpdm_t ctxt
)
2011 /* openfile driver function */
2013 return run_filechooser(a
, FALSE
);
2017 static mpdm_t
gtk_drv_savefile(mpdm_t a
, mpdm_t ctxt
)
2018 /* savefile driver function */
2020 return run_filechooser(a
, TRUE
);
2024 static mpdm_t
gtk_drv_update_ui(mpdm_t a
, mpdm_t ctxt
)
2036 static mpdm_t
gtk_drv_timer(mpdm_t a
, mpdm_t ctxt
)
2038 static guint prev
= 0;
2039 int msecs
= mpdm_ival(mpdm_aget(a
, 0));
2040 mpdm_t func
= mpdm_aget(a
, 1);
2042 /* previously defined one? remove */
2043 if (timer_func
!= NULL
)
2044 gtk_timeout_remove(prev
);
2046 /* if msecs and func are set, program timer */
2047 if (msecs
> 0 && func
!= NULL
)
2048 prev
= gtk_timeout_add(msecs
, timer_callback
, NULL
);
2051 mpdm_unref(timer_func
);
2058 static mpdm_t
gtk_drv_busy(mpdm_t a
, mpdm_t ctxt
)
2060 int onoff
= mpdm_ival(mpdm_aget(a
, 0));
2062 gdk_window_set_cursor(window
->window
,
2063 gdk_cursor_new(onoff
? GDK_WATCH
:
2066 while (gtk_events_pending())
2067 gtk_main_iteration();
2073 static mpdm_t
gtk_drv_main_loop(mpdm_t a
, mpdm_t ctxt
)
2076 if (!mp_exit_requested
) {
2077 gtk_drv_paint(mp_active(), 0);
2086 static mpdm_t
gtk_drv_shutdown(mpdm_t a
, mpdm_t ctxt
)
2091 if ((v
= mpdm_hget_s(mp
, L
"exit_message")) != NULL
) {
2092 mpdm_write_wcs(stdout
, mpdm_string(v
));
2100 static void register_functions(void)
2104 drv
= mpdm_hget_s(mp
, L
"drv");
2105 mpdm_hset_s(drv
, L
"main_loop", MPDM_X(gtk_drv_main_loop
));
2106 mpdm_hset_s(drv
, L
"shutdown", MPDM_X(gtk_drv_shutdown
));
2107 mpdm_hset_s(drv
, L
"clip_to_sys", MPDM_X(gtk_drv_clip_to_sys
));
2108 mpdm_hset_s(drv
, L
"sys_to_clip", MPDM_X(gtk_drv_sys_to_clip
));
2109 mpdm_hset_s(drv
, L
"update_ui", MPDM_X(gtk_drv_update_ui
));
2110 mpdm_hset_s(drv
, L
"timer", MPDM_X(gtk_drv_timer
));
2111 mpdm_hset_s(drv
, L
"busy", MPDM_X(gtk_drv_busy
));
2112 mpdm_hset_s(drv
, L
"alert", MPDM_X(gtk_drv_alert
));
2113 mpdm_hset_s(drv
, L
"confirm", MPDM_X(gtk_drv_confirm
));
2114 mpdm_hset_s(drv
, L
"openfile", MPDM_X(gtk_drv_openfile
));
2115 mpdm_hset_s(drv
, L
"savefile", MPDM_X(gtk_drv_savefile
));
2116 mpdm_hset_s(drv
, L
"form", MPDM_X(gtk_drv_form
));
2120 static mpdm_t
gtk_drv_startup(mpdm_t a
, mpdm_t ctxt
)
2121 /* driver initialization */
2130 GtkTargetEntry targets
[] = {
2131 {"text/plain", 0, 0},
2132 {"text/uri-list", 0, 1}
2135 register_functions();
2137 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
2139 gtk_window_set_title(GTK_WINDOW(window
), "mp " VERSION
);
2141 /* get real screen and pick a usable size for the main area */
2142 screen
= gtk_window_get_screen(GTK_WINDOW(window
));
2143 if (gdk_screen_get_n_monitors(screen
) > 1) {
2144 GdkRectangle monitor_one_size
;
2145 gdk_screen_get_monitor_geometry(screen
, 0, &monitor_one_size
);
2147 w
= (monitor_one_size
.width
* 3) / 4;
2148 h
= (monitor_one_size
.height
* 2) / 3;
2150 w
= (gdk_screen_get_width(screen
) * 3) / 4;
2151 h
= (gdk_screen_get_height(screen
) * 2) / 3;
2154 g_signal_connect(G_OBJECT(window
), "delete_event",
2155 G_CALLBACK(delete_event
), NULL
);
2157 g_signal_connect(G_OBJECT(window
), "destroy",
2158 G_CALLBACK(destroy
), NULL
);
2161 file_tabs
= gtk_notebook_new();
2162 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(file_tabs
), GTK_POS_TOP
);
2163 GTK_WIDGET_UNSET_FLAGS(file_tabs
, GTK_CAN_FOCUS
);
2164 gtk_notebook_set_scrollable(GTK_NOTEBOOK(file_tabs
), 1);
2166 vbox
= gtk_vbox_new(FALSE
, 2);
2167 gtk_container_add(GTK_CONTAINER(window
), vbox
);
2171 hbox
= gtk_hbox_new(FALSE
, 0);
2172 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
2173 gtk_box_pack_start(GTK_BOX(hbox
), menu_bar
, FALSE
, FALSE
, 0);
2174 gtk_box_pack_start(GTK_BOX(hbox
), file_tabs
, TRUE
, TRUE
, 0);
2176 gtk_notebook_popup_enable(GTK_NOTEBOOK(file_tabs
));
2178 /* horizontal box holding the text and the scrollbar */
2179 hbox
= gtk_hbox_new(FALSE
, 2);
2180 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, TRUE
, TRUE
, 0);
2182 /* the Minimum Profit area */
2183 area
= gtk_drawing_area_new();
2184 gtk_box_pack_start(GTK_BOX(hbox
), area
, TRUE
, TRUE
, 0);
2185 gtk_widget_set_size_request(GTK_WIDGET(area
), w
, h
);
2186 gtk_widget_set_events(GTK_WIDGET(area
), GDK_BUTTON_PRESS_MASK
|
2187 GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK
2188 | GDK_LEAVE_NOTIFY_MASK
);
2190 gtk_widget_set_double_buffered(area
, FALSE
);
2192 g_signal_connect(G_OBJECT(area
), "configure_event",
2193 G_CALLBACK(configure_event
), NULL
);
2195 g_signal_connect(G_OBJECT(area
), "expose_event",
2196 G_CALLBACK(expose_event
), NULL
);
2198 g_signal_connect(G_OBJECT(area
), "realize", G_CALLBACK(realize
), NULL
);
2200 g_signal_connect(G_OBJECT(window
), "key_press_event",
2201 G_CALLBACK(key_press_event
), NULL
);
2203 g_signal_connect(G_OBJECT(window
), "key_release_event",
2204 G_CALLBACK(key_release_event
), NULL
);
2206 g_signal_connect(G_OBJECT(area
), "button_press_event",
2207 G_CALLBACK(button_press_event
), NULL
);
2209 g_signal_connect(G_OBJECT(area
), "button_release_event",
2210 G_CALLBACK(button_release_event
), NULL
);
2212 g_signal_connect(G_OBJECT(area
), "motion_notify_event",
2213 G_CALLBACK(motion_notify_event
), NULL
);
2215 g_signal_connect(G_OBJECT(area
), "selection_clear_event",
2216 G_CALLBACK(selection_clear_event
), NULL
);
2218 g_signal_connect(G_OBJECT(area
), "selection_get",
2219 G_CALLBACK(selection_get
), NULL
);
2221 g_signal_connect(G_OBJECT(area
), "selection_received",
2222 G_CALLBACK(selection_received
), NULL
);
2224 g_signal_connect(G_OBJECT(area
), "scroll_event",
2225 G_CALLBACK(scroll_event
), NULL
);
2227 gtk_drag_dest_set(area
, GTK_DEST_DEFAULT_ALL
, targets
,
2228 sizeof(targets
) / sizeof(GtkTargetEntry
),
2230 g_signal_connect(G_OBJECT(area
), "drag_data_received",
2231 G_CALLBACK(drag_data_received
), NULL
);
2233 gtk_selection_add_target(area
, GDK_SELECTION_PRIMARY
,
2234 GDK_SELECTION_TYPE_STRING
, 1);
2236 g_signal_connect(G_OBJECT(file_tabs
), "switch_page",
2237 G_CALLBACK(switch_page
), NULL
);
2240 scrollbar
= gtk_vscrollbar_new(NULL
);
2241 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, FALSE
, 0);
2243 g_signal_connect(G_OBJECT
2244 (gtk_range_get_adjustment(GTK_RANGE(scrollbar
))),
2245 "value_changed", G_CALLBACK(value_changed
), NULL
);
2247 /* the status bar */
2248 status
= gtk_label_new("mp " VERSION
);
2249 gtk_box_pack_start(GTK_BOX(vbox
), status
, FALSE
, FALSE
, 0);
2250 gtk_misc_set_alignment(GTK_MISC(status
), 0, 0.5);
2251 gtk_label_set_justify(GTK_LABEL(status
), GTK_JUSTIFY_LEFT
);
2253 gtk_widget_show_all(window
);
2255 /* set application icon */
2256 pixmap
= gdk_pixmap_create_from_xpm_d(window
->window
,
2257 &mask
, NULL
, mp_xpm
);
2258 gdk_window_set_icon(window
->window
, NULL
, pixmap
, mask
);
2262 if ((v
= mpdm_hget_s(mp
, L
"config")) != NULL
&&
2263 mpdm_ival(mpdm_hget_s(v
, L
"maximize")) > 0)
2270 int gtk_drv_detect(int *argc
, char ***argv
)
2275 for (n
= 0; n
< *argc
; n
++) {
2276 if (strcmp(argv
[0][n
], "-txt") == 0 ||
2277 strcmp(argv
[0][n
], "-h") == 0)
2281 if (!gtk_init_check(argc
, argv
))
2284 drv
= mpdm_hget_s(mp
, L
"drv");
2285 mpdm_hset_s(drv
, L
"id", MPDM_LS(L
"gtk"));
2286 mpdm_hset_s(drv
, L
"startup", MPDM_X(gtk_drv_startup
));
2291 #endif /* CONFOPT_GTK */