3 Minimum Profit - Programmer Text Editor
7 Copyright (C) 1991-2011 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 GtkIMContext
*im
= NULL
;
60 /* character read from the keyboard */
61 static wchar_t im_char
[2];
63 /* font information */
64 static int font_width
= 0;
65 static int font_height
= 0;
66 static PangoFontDescription
*font
= NULL
;
69 static GdkColor
*inks
= NULL
;
70 static GdkColor
*papers
= NULL
;
71 static int *underlines
= NULL
;
73 /* true if the selection is ours */
74 static int got_selection
= 0;
76 /* hack for active waiting for the selection */
77 static int wait_for_selection
= 0;
79 /* global modal status */
80 /* code for the 'normal' attribute */
81 static int normal_attr
= 0;
83 /* mp.drv.form() controls */
85 static GtkWidget
**form_widgets
= NULL
;
86 static mpdm_t form_args
= NULL
;
87 static mpdm_t form_values
= NULL
;
90 static int mouse_down
= 0;
93 static mpdm_t timer_func
= NULL
;
95 /* maximize wanted? */
96 static int maximize
= 0;
100 /** support functions **/
104 static char *wcs_to_utf8(const wchar_t * wptr
)
105 /* converts a wcs to utf-8 */
112 /* do the conversion */
113 ptr
= g_convert((const gchar
*) wptr
, (i
+ 1) * sizeof(wchar_t),
114 "UTF-8", "WCHAR_T", NULL
, &o
, NULL
);
120 static char *v_to_utf8(mpdm_t v
)
126 ptr
= wcs_to_utf8(mpdm_string(v
));
133 static wchar_t *utf8_to_wcs(const char *ptr
)
134 /* converts utf-8 to wcs */
141 /* do the conversion */
142 wptr
= (wchar_t *) g_convert((gchar
*) ptr
, i
+ 1,
143 "WCHAR_T", "UTF-8", NULL
, &o
, NULL
);
149 static void update_window_size(void)
150 /* updates the viewport size in characters */
156 /* get font metrics */
157 pa
= gtk_widget_create_pango_layout(area
, "m");
158 pango_layout_set_font_description(pa
, font
);
159 pango_layout_get_pixel_size(pa
, &font_width
, &font_height
);
162 /* calculate the size in chars */
163 tx
= (area
->allocation
.width
/ font_width
);
164 ty
= (area
->allocation
.height
/ font_height
) + 1;
166 /* store the 'window' size */
167 v
= mpdm_hget_s(mp
, L
"window");
168 mpdm_hset_s(v
, L
"tx", MPDM_I(tx
));
169 mpdm_hset_s(v
, L
"ty", MPDM_I(ty
));
171 /* rebuild the pixmap for the double buffer */
175 static void build_fonts(void)
176 /* builds the fonts */
180 const char *font_face
= "Mono";
185 pango_font_description_free(font
);
187 /* get current configuration */
188 if ((c
= mpdm_hget_s(mp
, L
"config")) != NULL
) {
191 if ((v
= mpdm_hget_s(c
, L
"font_size")) != NULL
)
192 font_size
= mpdm_ival(v
);
194 mpdm_hset_s(c
, L
"font_size", MPDM_I(font_size
));
196 if ((v
= mpdm_hget_s(c
, L
"font_face")) != NULL
) {
197 w
= mpdm_ref(MPDM_2MBS(v
->data
));
201 mpdm_hset_s(c
, L
"font_face", MPDM_MBS(font_face
));
204 snprintf(tmp
, sizeof(tmp
) - 1, "%s %d", font_face
, font_size
);
205 tmp
[sizeof(tmp
) - 1] = '\0';
207 font
= pango_font_description_from_string(tmp
);
208 update_window_size();
214 static void build_color(GdkColor
* gdkcolor
, int rgb
)
218 gdkcolor
->blue
= (rgb
& 0x000000ff) << 8;
219 gdkcolor
->green
= (rgb
& 0x0000ff00);
220 gdkcolor
->red
= (rgb
& 0x00ff0000) >> 8;
221 gdk_colormap_alloc_color(gdk_colormap_get_system(), gdkcolor
, FALSE
,
226 static void build_colors(void)
227 /* builds the colors */
234 /* gets the color definitions and attribute names */
235 colors
= mpdm_hget_s(mp
, L
"colors");
236 l
= mpdm_ref(mpdm_keys(colors
));
239 /* redim the structures */
240 inks
= realloc(inks
, sizeof(GdkColor
) * s
);
241 papers
= realloc(papers
, sizeof(GdkColor
) * s
);
242 underlines
= realloc(underlines
, sizeof(int) * s
);
244 /* loop the colors */
245 for (n
= 0; n
< s
&& (c
= mpdm_aget(l
, n
)) != NULL
; n
++) {
246 mpdm_t d
= mpdm_hget(colors
, c
);
247 mpdm_t v
= mpdm_hget_s(d
, L
"gui");
249 /* store the 'normal' attribute */
250 if (wcscmp(mpdm_string(c
), L
"normal") == 0)
254 mpdm_hset_s(d
, L
"attr", MPDM_I(n
));
256 build_color(&inks
[n
], mpdm_ival(mpdm_aget(v
, 0)));
257 build_color(&papers
[n
], mpdm_ival(mpdm_aget(v
, 1)));
260 v
= mpdm_hget_s(d
, L
"flags");
261 underlines
[n
] = mpdm_seek_s(v
, L
"underline", 1) != -1 ? 1 : 0;
263 if (mpdm_seek_s(v
, L
"reverse", 1) != -1) {
276 /** menu functions **/
278 static void redraw(void);
280 static void menu_item_callback(mpdm_t action
)
281 /* menu click callback */
283 mp_process_action(action
);
286 if (mp_exit_requested
)
291 static void build_submenu(GtkWidget
* menu
, mpdm_t labels
)
292 /* build a submenu */
295 GtkWidget
*menu_item
;
299 for (n
= 0; n
< mpdm_size(labels
); n
++) {
301 mpdm_t v
= mpdm_aget(labels
, n
);
303 /* if the action is a separator... */
304 if (*((wchar_t *) v
->data
) == L
'-')
305 menu_item
= gtk_menu_item_new();
309 ptr
= v_to_utf8(mp_menu_label(v
));
310 menu_item
= gtk_menu_item_new_with_label(ptr
);
314 gtk_menu_append(GTK_MENU(menu
), menu_item
);
315 g_signal_connect_swapped(G_OBJECT(menu_item
), "activate",
316 G_CALLBACK(menu_item_callback
), v
);
317 gtk_widget_show(menu_item
);
324 static void build_menu(void)
325 /* builds the menu */
327 static mpdm_t prev_menu
= NULL
;
331 /* gets the current menu */
332 if ((m
= mpdm_hget_s(mp
, L
"menu")) == NULL
)
335 /* if it's the same, do nothing */
336 if (mpdm_cmp(m
, prev_menu
) == 0)
339 /* create a new menu */
340 menu_bar
= gtk_menu_bar_new();
342 for (n
= 0; n
< mpdm_size(m
); n
++) {
347 GtkWidget
*menu_item
;
350 /* get the label and the items */
351 mi
= mpdm_aget(m
, n
);
352 v
= mpdm_aget(mi
, 0);
354 if ((ptr
= v_to_utf8(mpdm_gettext(v
))) == NULL
)
357 /* change the & by _ for the mnemonic */
358 for (i
= 0; ptr
[i
]; i
++)
362 /* add the menu and the label */
363 menu
= gtk_menu_new();
364 menu_item
= gtk_menu_item_new_with_mnemonic(ptr
);
367 gtk_widget_show(menu_item
);
368 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item
), menu
);
369 gtk_menu_bar_append(GTK_MENU_BAR(menu_bar
), menu_item
);
371 /* now loop the items */
372 build_submenu(menu
, mpdm_aget(mi
, 1));
377 /** main area drawing functions **/
379 static void switch_page(GtkNotebook
* notebook
, gpointer
* page
,
380 gint pg_num
, gpointer data
)
381 /* 'switch_page' handler (filetabs) */
383 /* sets the active one */
384 mpdm_hset_s(mp
, L
"active_i", MPDM_I(pg_num
));
386 gtk_widget_grab_focus(area
);
391 static void draw_filetabs(void)
392 /* draws the filetabs */
394 static mpdm_t last
= NULL
;
398 names
= mpdm_ref(mp_get_doc_names());
400 /* disconnect redraw signal to avoid infinite loops */
401 g_signal_handlers_disconnect_by_func(G_OBJECT(file_tabs
),
402 G_CALLBACK(switch_page
), NULL
);
404 /* is the list different from the previous one? */
405 if (mpdm_cmp(names
, last
) != 0) {
407 /* delete the current tabs */
408 for (n
= 0; n
< mpdm_size(last
); n
++)
409 gtk_notebook_remove_page(GTK_NOTEBOOK(file_tabs
), 0);
411 /* create the new ones */
412 for (n
= 0; n
< mpdm_size(names
); n
++) {
416 mpdm_t v
= mpdm_aget(names
, n
);
418 if ((ptr
= v_to_utf8(v
)) != NULL
) {
419 p
= gtk_label_new(ptr
);
422 f
= gtk_frame_new(NULL
);
425 gtk_notebook_append_page(GTK_NOTEBOOK(file_tabs
), f
, p
);
431 /* store for the next time */
433 last
= mpdm_ref(names
);
438 /* set the active one */
439 gtk_notebook_set_current_page(GTK_NOTEBOOK(file_tabs
),
440 mpdm_ival(mpdm_hget_s(mp
, L
"active_i")));
442 /* reconnect signal */
443 g_signal_connect(G_OBJECT(file_tabs
), "switch_page",
444 G_CALLBACK(switch_page
), NULL
);
446 gtk_widget_grab_focus(area
);
450 static void draw_status(void)
451 /* draws the status line */
455 if ((ptr
= v_to_utf8(mp_build_status_line())) != NULL
) {
456 gtk_label_set_text(GTK_LABEL(status
), ptr
);
462 static gint
scroll_event(GtkWidget
* widget
, GdkEventScroll
* event
)
463 /* 'scroll_event' handler (mouse wheel) */
467 switch (event
->direction
) {
469 ptr
= L
"mouse-wheel-up";
471 case GDK_SCROLL_DOWN
:
472 ptr
= L
"mouse-wheel-down";
474 case GDK_SCROLL_LEFT
:
475 ptr
= L
"mouse-wheel-left";
477 case GDK_SCROLL_RIGHT
:
478 ptr
= L
"mouse-wheel-right";
483 mp_process_event(MPDM_S(ptr
));
491 static void value_changed(GtkAdjustment
* adj
, gpointer
* data
)
492 /* 'value_changed' handler (scrollbar) */
494 int i
= (int) gtk_adjustment_get_value(adj
);
499 /* get current y position */
501 txt
= mpdm_hget_s(doc
, L
"txt");
502 y
= mpdm_ival(mpdm_hget_s(txt
, L
"y"));
504 /* if it's different, set and redraw */
507 mpdm_hset_s(txt
, L
"vy", MPDM_I(i
));
513 static void draw_scrollbar(void)
514 /* updates the scrollbar */
516 GtkAdjustment
*adjustment
;
521 /* gets the active document */
522 if ((d
= mp_active()) == NULL
)
525 /* get the coordinates */
526 v
= mpdm_hget_s(d
, L
"txt");
527 pos
= mpdm_ival(mpdm_hget_s(v
, L
"vy"));
528 max
= mpdm_size(mpdm_hget_s(v
, L
"lines"));
530 v
= mpdm_hget_s(mp
, L
"window");
531 size
= mpdm_ival(mpdm_hget_s(v
, L
"ty"));
533 adjustment
= gtk_range_get_adjustment(GTK_RANGE(scrollbar
));
535 /* disconnect to avoid infinite loops */
536 g_signal_handlers_disconnect_by_func(G_OBJECT(adjustment
),
537 G_CALLBACK(value_changed
), NULL
);
539 gtk_adjustment_set_step_increment(adjustment
, (gdouble
) 1);
540 gtk_adjustment_set_upper(adjustment
, (gdouble
) max
);
541 gtk_adjustment_set_page_size(adjustment
, (gdouble
) size
);
542 gtk_adjustment_set_page_increment(adjustment
, (gdouble
) size
);
543 gtk_adjustment_set_value(adjustment
, (gdouble
) pos
);
545 gtk_range_set_adjustment(GTK_RANGE(scrollbar
), adjustment
);
547 gtk_adjustment_changed(adjustment
);
548 gtk_adjustment_value_changed(adjustment
);
551 g_signal_connect(G_OBJECT
552 (gtk_range_get_adjustment(GTK_RANGE(scrollbar
))),
553 "value_changed", G_CALLBACK(value_changed
), NULL
);
557 static void gtk_drv_paint(mpdm_t doc
, int optimize
)
558 /* GTK document draw function */
566 gtk_window_maximize(GTK_WINDOW(window
));
568 /* no gc? create it */
572 if ((d
= mp_draw(doc
, optimize
)) == NULL
)
581 gr
.width
= area
->allocation
.width
;
584 gr
.width
= gtk_widget_get_allocated_width(area
);
587 gr
.height
= font_height
;
589 cr
= gdk_cairo_create(gtk_widget_get_window(area
));
590 for (n
= 0; n
< mpdm_size(d
); n
++) {
593 mpdm_t l
= mpdm_aget(d
, n
);
600 /* create the pango stuff */
601 pl
= gtk_widget_create_pango_layout(area
, NULL
);
602 pango_layout_set_font_description(pl
, font
);
603 pal
= pango_attr_list_new();
605 for (m
= u
= p
= 0; m
< mpdm_size(l
); m
++, u
= p
) {
611 /* get the attribute and the string */
612 attr
= mpdm_ival(mpdm_aget(l
, m
++));
615 /* convert the string to utf8 */
618 /* add to the full line */
619 str
= mpdm_poke(str
, &p
, ptr
, strlen(ptr
), 1);
623 /* create the background if it's
624 different from the default */
625 if (papers
[attr
].red
!= papers
[normal_attr
].red
||
626 papers
[attr
].green
!= papers
[normal_attr
].green
||
627 papers
[attr
].blue
!= papers
[normal_attr
].blue
) {
628 pa
= pango_attr_background_new(papers
[attr
].red
,
635 pango_attr_list_insert(pal
, pa
);
639 if (underlines
[attr
]) {
640 pa
= pango_attr_underline_new(TRUE
);
645 pango_attr_list_insert(pal
, pa
);
648 /* foreground color */
649 pa
= pango_attr_foreground_new(inks
[attr
].red
,
656 pango_attr_list_insert(pal
, pa
);
659 /* store the attributes */
660 pango_layout_set_attributes(pl
, pal
);
661 pango_attr_list_unref(pal
);
663 /* store and free the text */
664 pango_layout_set_text(pl
, str
, p
);
667 /* draw the background */
668 gdk_cairo_set_source_color(cr
, &papers
[normal_attr
]);
669 cairo_rectangle(cr
, 0, n
* font_height
, gr
.width
, gr
.height
);
673 cairo_move_to(cr
, 2, n
* font_height
);
674 pango_cairo_show_layout(cr
, pl
);
688 static void redraw(void)
690 if (mpdm_size(mpdm_hget_s(mp
, L
"docs")))
691 gtk_drv_paint(mp_active(), 0);
695 static gint
delete_event(GtkWidget
* w
, GdkEvent
* e
, gpointer data
)
696 /* 'delete_event' handler */
698 mp_process_event(MPDM_LS(L
"close-window"));
700 return mp_exit_requested
? FALSE
: TRUE
;
704 static void destroy(GtkWidget
* w
, gpointer data
)
705 /* 'destroy' handler */
711 static gint
key_release_event(GtkWidget
* widget
, GdkEventKey
* event
,
713 /* 'key_release_event' handler */
715 if (mp_keypress_throttle(0))
716 gtk_drv_paint(mp_active(), 0);
723 #define MP_KEY_Up GDK_Up
724 #define MP_KEY_Down GDK_Down
725 #define MP_KEY_Left GDK_Left
726 #define MP_KEY_Right GDK_Right
727 #define MP_KEY_Prior GDK_Prior
728 #define MP_KEY_Next GDK_Next
729 #define MP_KEY_Home GDK_Home
730 #define MP_KEY_End GDK_End
731 #define MP_KEY_space GDK_space
732 #define MP_KEY_KP_Add GDK_KP_Add
733 #define MP_KEY_KP_Subtract GDK_KP_Subtract
734 #define MP_KEY_KP_Multiply GDK_KP_Multiply
735 #define MP_KEY_KP_Divide GDK_KP_Divide
736 #define MP_KEY_F1 GDK_F1
737 #define MP_KEY_F2 GDK_F2
738 #define MP_KEY_F3 GDK_F3
739 #define MP_KEY_F4 GDK_F4
740 #define MP_KEY_F5 GDK_F5
741 #define MP_KEY_F6 GDK_F6
742 #define MP_KEY_F7 GDK_F7
743 #define MP_KEY_F8 GDK_F8
744 #define MP_KEY_F9 GDK_F9
745 #define MP_KEY_F10 GDK_F10
746 #define MP_KEY_F11 GDK_F11
747 #define MP_KEY_F12 GDK_F12
748 #define MP_KEY_KP_Enter GDK_KP_Enter
749 #define MP_KEY_Return GDK_Return
750 #define MP_KEY_Cyrillic_ve GDK_Cyrillic_ve
751 #define MP_KEY_Cyrillic_a GDK_Cyrillic_a
752 #define MP_KEY_Cyrillic_tse GDK_Cyrillic_tse
753 #define MP_KEY_Cyrillic_de GDK_Cyrillic_de
754 #define MP_KEY_Cyrillic_ie GDK_Cyrillic_ie
755 #define MP_KEY_Cyrillic_ef GDK_Cyrillic_ef
756 #define MP_KEY_Cyrillic_ghe GDK_Cyrillic_ghe
757 #define MP_KEY_Cyrillic_i GDK_Cyrillic_i
758 #define MP_KEY_Cyrillic_shorti GDK_Cyrillic_shorti
759 #define MP_KEY_Cyrillic_ka GDK_Cyrillic_ka
760 #define MP_KEY_Cyrillic_el GDK_Cyrillic_el
761 #define MP_KEY_Cyrillic_em GDK_Cyrillic_em
762 #define MP_KEY_Cyrillic_en GDK_Cyrillic_en
763 #define MP_KEY_Cyrillic_o GDK_Cyrillic_o
764 #define MP_KEY_Cyrillic_pe GDK_Cyrillic_pe
765 #define MP_KEY_Cyrillic_ya GDK_Cyrillic_ya
766 #define MP_KEY_Cyrillic_er GDK_Cyrillic_er
767 #define MP_KEY_Cyrillic_es GDK_Cyrillic_es
768 #define MP_KEY_Cyrillic_te GDK_Cyrillic_te
769 #define MP_KEY_Cyrillic_softsign GDK_Cyrillic_softsign
770 #define MP_KEY_Cyrillic_yeru GDK_Cyrillic_yeru
771 #define MP_KEY_Cyrillic_ze GDK_Cyrillic_ze
772 #define MP_KEY_Cyrillic_sha GDK_Cyrillic_sha
773 #define MP_KEY_Cyrillic_e GDK_Cyrillic_e
774 #define MP_KEY_Cyrillic_shcha GDK_Cyrillic_shcha
775 #define MP_KEY_Cyrillic_che GDK_Cyrillic_che
776 #define MP_KEY_Up GDK_Up
777 #define MP_KEY_Down GDK_Down
778 #define MP_KEY_Left GDK_Left
779 #define MP_KEY_Right GDK_Right
780 #define MP_KEY_Prior GDK_Prior
781 #define MP_KEY_Next GDK_Next
782 #define MP_KEY_Home GDK_Home
783 #define MP_KEY_End GDK_End
784 #define MP_KEY_space GDK_space
785 #define MP_KEY_KP_Add GDK_KP_Add
786 #define MP_KEY_KP_Subtract GDK_KP_Subtract
787 #define MP_KEY_KP_Multiply GDK_KP_Multiply
788 #define MP_KEY_KP_Divide GDK_KP_Divide
789 #define MP_KEY_F1 GDK_F1
790 #define MP_KEY_F2 GDK_F2
791 #define MP_KEY_F3 GDK_F3
792 #define MP_KEY_F4 GDK_F4
793 #define MP_KEY_F5 GDK_F5
794 #define MP_KEY_F6 GDK_F6
795 #define MP_KEY_F7 GDK_F7
796 #define MP_KEY_F8 GDK_F8
797 #define MP_KEY_F9 GDK_F9
798 #define MP_KEY_F10 GDK_F10
799 #define MP_KEY_F11 GDK_F11
800 #define MP_KEY_F12 GDK_F12
801 #define MP_KEY_KP_Enter GDK_KP_Enter
802 #define MP_KEY_Return GDK_Return
803 #define MP_KEY_Cyrillic_ve GDK_Cyrillic_ve
804 #define MP_KEY_Cyrillic_a GDK_Cyrillic_a
805 #define MP_KEY_Cyrillic_tse GDK_Cyrillic_tse
806 #define MP_KEY_Cyrillic_de GDK_Cyrillic_de
807 #define MP_KEY_Cyrillic_ie GDK_Cyrillic_ie
808 #define MP_KEY_Cyrillic_ef GDK_Cyrillic_ef
809 #define MP_KEY_Cyrillic_ghe GDK_Cyrillic_ghe
810 #define MP_KEY_Cyrillic_i GDK_Cyrillic_i
811 #define MP_KEY_Cyrillic_shorti GDK_Cyrillic_shorti
812 #define MP_KEY_Cyrillic_ka GDK_Cyrillic_ka
813 #define MP_KEY_Cyrillic_el GDK_Cyrillic_el
814 #define MP_KEY_Cyrillic_em GDK_Cyrillic_em
815 #define MP_KEY_Cyrillic_en GDK_Cyrillic_en
816 #define MP_KEY_Cyrillic_o GDK_Cyrillic_o
817 #define MP_KEY_Cyrillic_pe GDK_Cyrillic_pe
818 #define MP_KEY_Cyrillic_ya GDK_Cyrillic_ya
819 #define MP_KEY_Cyrillic_er GDK_Cyrillic_er
820 #define MP_KEY_Cyrillic_es GDK_Cyrillic_es
821 #define MP_KEY_Cyrillic_te GDK_Cyrillic_te
822 #define MP_KEY_Cyrillic_softsign GDK_Cyrillic_softsign
823 #define MP_KEY_Cyrillic_yeru GDK_Cyrillic_yeru
824 #define MP_KEY_Cyrillic_ze GDK_Cyrillic_ze
825 #define MP_KEY_Cyrillic_sha GDK_Cyrillic_sha
826 #define MP_KEY_Cyrillic_e GDK_Cyrillic_e
827 #define MP_KEY_Cyrillic_shcha GDK_Cyrillic_shcha
828 #define MP_KEY_Cyrillic_che GDK_Cyrillic_che
829 #define MP_KEY_Up GDK_Up
830 #define MP_KEY_Down GDK_Down
831 #define MP_KEY_Left GDK_Left
832 #define MP_KEY_Right GDK_Right
833 #define MP_KEY_Prior GDK_Prior
834 #define MP_KEY_Next GDK_Next
835 #define MP_KEY_Home GDK_Home
836 #define MP_KEY_End GDK_End
837 #define MP_KEY_space GDK_space
838 #define MP_KEY_KP_Add GDK_KP_Add
839 #define MP_KEY_KP_Subtract GDK_KP_Subtract
840 #define MP_KEY_KP_Multiply GDK_KP_Multiply
841 #define MP_KEY_KP_Divide GDK_KP_Divide
842 #define MP_KEY_F1 GDK_F1
843 #define MP_KEY_F2 GDK_F2
844 #define MP_KEY_F3 GDK_F3
845 #define MP_KEY_F4 GDK_F4
846 #define MP_KEY_F5 GDK_F5
847 #define MP_KEY_F6 GDK_F6
848 #define MP_KEY_F7 GDK_F7
849 #define MP_KEY_F8 GDK_F8
850 #define MP_KEY_F9 GDK_F9
851 #define MP_KEY_F10 GDK_F10
852 #define MP_KEY_F11 GDK_F11
853 #define MP_KEY_F12 GDK_F12
854 #define MP_KEY_Insert GDK_Insert
855 #define MP_KEY_BackSpace GDK_BackSpace
856 #define MP_KEY_Delete GDK_Delete
857 #define MP_KEY_KP_Enter GDK_KP_Enter
858 #define MP_KEY_Return GDK_Return
859 #define MP_KEY_Tab GDK_Tab
860 #define MP_KEY_ISO_Left_Tab GDK_ISO_Left_Tab
861 #define MP_KEY_Escape GDK_Escape
862 #endif /* CONFOPT_GTK == 2 */
865 #define MP_KEY_Up GDK_KEY_Up
866 #define MP_KEY_Down GDK_KEY_Down
867 #define MP_KEY_Left GDK_KEY_Left
868 #define MP_KEY_Right GDK_KEY_Right
869 #define MP_KEY_Prior GDK_KEY_Prior
870 #define MP_KEY_Next GDK_KEY_Next
871 #define MP_KEY_Home GDK_KEY_Home
872 #define MP_KEY_End GDK_KEY_End
873 #define MP_KEY_space GDK_KEY_space
874 #define MP_KEY_KP_Add GDK_KEY_KP_Add
875 #define MP_KEY_KP_Subtract GDK_KEY_KP_Subtract
876 #define MP_KEY_KP_Multiply GDK_KEY_KP_Multiply
877 #define MP_KEY_KP_Divide GDK_KEY_KP_Divide
878 #define MP_KEY_F1 GDK_KEY_F1
879 #define MP_KEY_F2 GDK_KEY_F2
880 #define MP_KEY_F3 GDK_KEY_F3
881 #define MP_KEY_F4 GDK_KEY_F4
882 #define MP_KEY_F5 GDK_KEY_F5
883 #define MP_KEY_F6 GDK_KEY_F6
884 #define MP_KEY_F7 GDK_KEY_F7
885 #define MP_KEY_F8 GDK_KEY_F8
886 #define MP_KEY_F9 GDK_KEY_F9
887 #define MP_KEY_F10 GDK_KEY_F10
888 #define MP_KEY_F11 GDK_KEY_F11
889 #define MP_KEY_F12 GDK_KEY_F12
890 #define MP_KEY_KP_Enter GDK_KEY_KP_Enter
891 #define MP_KEY_Return GDK_KEY_Return
892 #define MP_KEY_Cyrillic_ve GDK_KEY_Cyrillic_ve
893 #define MP_KEY_Cyrillic_a GDK_KEY_Cyrillic_a
894 #define MP_KEY_Cyrillic_tse GDK_KEY_Cyrillic_tse
895 #define MP_KEY_Cyrillic_de GDK_KEY_Cyrillic_de
896 #define MP_KEY_Cyrillic_ie GDK_KEY_Cyrillic_ie
897 #define MP_KEY_Cyrillic_ef GDK_KEY_Cyrillic_ef
898 #define MP_KEY_Cyrillic_ghe GDK_KEY_Cyrillic_ghe
899 #define MP_KEY_Cyrillic_i GDK_KEY_Cyrillic_i
900 #define MP_KEY_Cyrillic_shorti GDK_KEY_Cyrillic_shorti
901 #define MP_KEY_Cyrillic_ka GDK_KEY_Cyrillic_ka
902 #define MP_KEY_Cyrillic_el GDK_KEY_Cyrillic_el
903 #define MP_KEY_Cyrillic_em GDK_KEY_Cyrillic_em
904 #define MP_KEY_Cyrillic_en GDK_KEY_Cyrillic_en
905 #define MP_KEY_Cyrillic_o GDK_KEY_Cyrillic_o
906 #define MP_KEY_Cyrillic_pe GDK_KEY_Cyrillic_pe
907 #define MP_KEY_Cyrillic_ya GDK_KEY_Cyrillic_ya
908 #define MP_KEY_Cyrillic_er GDK_KEY_Cyrillic_er
909 #define MP_KEY_Cyrillic_es GDK_KEY_Cyrillic_es
910 #define MP_KEY_Cyrillic_te GDK_KEY_Cyrillic_te
911 #define MP_KEY_Cyrillic_softsign GDK_KEY_Cyrillic_softsign
912 #define MP_KEY_Cyrillic_yeru GDK_KEY_Cyrillic_yeru
913 #define MP_KEY_Cyrillic_ze GDK_KEY_Cyrillic_ze
914 #define MP_KEY_Cyrillic_sha GDK_KEY_Cyrillic_sha
915 #define MP_KEY_Cyrillic_e GDK_KEY_Cyrillic_e
916 #define MP_KEY_Cyrillic_shcha GDK_KEY_Cyrillic_shcha
917 #define MP_KEY_Cyrillic_che GDK_KEY_Cyrillic_che
918 #define MP_KEY_Up GDK_KEY_Up
919 #define MP_KEY_Down GDK_KEY_Down
920 #define MP_KEY_Left GDK_KEY_Left
921 #define MP_KEY_Right GDK_KEY_Right
922 #define MP_KEY_Prior GDK_KEY_Prior
923 #define MP_KEY_Next GDK_KEY_Next
924 #define MP_KEY_Home GDK_KEY_Home
925 #define MP_KEY_End GDK_KEY_End
926 #define MP_KEY_space GDK_KEY_space
927 #define MP_KEY_KP_Add GDK_KEY_KP_Add
928 #define MP_KEY_KP_Subtract GDK_KEY_KP_Subtract
929 #define MP_KEY_KP_Multiply GDK_KEY_KP_Multiply
930 #define MP_KEY_KP_Divide GDK_KEY_KP_Divide
931 #define MP_KEY_F1 GDK_KEY_F1
932 #define MP_KEY_F2 GDK_KEY_F2
933 #define MP_KEY_F3 GDK_KEY_F3
934 #define MP_KEY_F4 GDK_KEY_F4
935 #define MP_KEY_F5 GDK_KEY_F5
936 #define MP_KEY_F6 GDK_KEY_F6
937 #define MP_KEY_F7 GDK_KEY_F7
938 #define MP_KEY_F8 GDK_KEY_F8
939 #define MP_KEY_F9 GDK_KEY_F9
940 #define MP_KEY_F10 GDK_KEY_F10
941 #define MP_KEY_F11 GDK_KEY_F11
942 #define MP_KEY_F12 GDK_KEY_F12
943 #define MP_KEY_KP_Enter GDK_KEY_KP_Enter
944 #define MP_KEY_Return GDK_KEY_Return
945 #define MP_KEY_Cyrillic_ve GDK_KEY_Cyrillic_ve
946 #define MP_KEY_Cyrillic_a GDK_KEY_Cyrillic_a
947 #define MP_KEY_Cyrillic_tse GDK_KEY_Cyrillic_tse
948 #define MP_KEY_Cyrillic_de GDK_KEY_Cyrillic_de
949 #define MP_KEY_Cyrillic_ie GDK_KEY_Cyrillic_ie
950 #define MP_KEY_Cyrillic_ef GDK_KEY_Cyrillic_ef
951 #define MP_KEY_Cyrillic_ghe GDK_KEY_Cyrillic_ghe
952 #define MP_KEY_Cyrillic_i GDK_KEY_Cyrillic_i
953 #define MP_KEY_Cyrillic_shorti GDK_KEY_Cyrillic_shorti
954 #define MP_KEY_Cyrillic_ka GDK_KEY_Cyrillic_ka
955 #define MP_KEY_Cyrillic_el GDK_KEY_Cyrillic_el
956 #define MP_KEY_Cyrillic_em GDK_KEY_Cyrillic_em
957 #define MP_KEY_Cyrillic_en GDK_KEY_Cyrillic_en
958 #define MP_KEY_Cyrillic_o GDK_KEY_Cyrillic_o
959 #define MP_KEY_Cyrillic_pe GDK_KEY_Cyrillic_pe
960 #define MP_KEY_Cyrillic_ya GDK_KEY_Cyrillic_ya
961 #define MP_KEY_Cyrillic_er GDK_KEY_Cyrillic_er
962 #define MP_KEY_Cyrillic_es GDK_KEY_Cyrillic_es
963 #define MP_KEY_Cyrillic_te GDK_KEY_Cyrillic_te
964 #define MP_KEY_Cyrillic_softsign GDK_KEY_Cyrillic_softsign
965 #define MP_KEY_Cyrillic_yeru GDK_KEY_Cyrillic_yeru
966 #define MP_KEY_Cyrillic_ze GDK_KEY_Cyrillic_ze
967 #define MP_KEY_Cyrillic_sha GDK_KEY_Cyrillic_sha
968 #define MP_KEY_Cyrillic_e GDK_KEY_Cyrillic_e
969 #define MP_KEY_Cyrillic_shcha GDK_KEY_Cyrillic_shcha
970 #define MP_KEY_Cyrillic_che GDK_KEY_Cyrillic_che
971 #define MP_KEY_Up GDK_KEY_Up
972 #define MP_KEY_Down GDK_KEY_Down
973 #define MP_KEY_Left GDK_KEY_Left
974 #define MP_KEY_Right GDK_KEY_Right
975 #define MP_KEY_Prior GDK_KEY_Prior
976 #define MP_KEY_Next GDK_KEY_Next
977 #define MP_KEY_Home GDK_KEY_Home
978 #define MP_KEY_End GDK_KEY_End
979 #define MP_KEY_space GDK_KEY_space
980 #define MP_KEY_KP_Add GDK_KEY_KP_Add
981 #define MP_KEY_KP_Subtract GDK_KEY_KP_Subtract
982 #define MP_KEY_KP_Multiply GDK_KEY_KP_Multiply
983 #define MP_KEY_KP_Divide GDK_KEY_KP_Divide
984 #define MP_KEY_F1 GDK_KEY_F1
985 #define MP_KEY_F2 GDK_KEY_F2
986 #define MP_KEY_F3 GDK_KEY_F3
987 #define MP_KEY_F4 GDK_KEY_F4
988 #define MP_KEY_F5 GDK_KEY_F5
989 #define MP_KEY_F6 GDK_KEY_F6
990 #define MP_KEY_F7 GDK_KEY_F7
991 #define MP_KEY_F8 GDK_KEY_F8
992 #define MP_KEY_F9 GDK_KEY_F9
993 #define MP_KEY_F10 GDK_KEY_F10
994 #define MP_KEY_F11 GDK_KEY_F11
995 #define MP_KEY_F12 GDK_KEY_F12
996 #define MP_KEY_Insert GDK_KEY_Insert
997 #define MP_KEY_BackSpace GDK_KEY_BackSpace
998 #define MP_KEY_Delete GDK_KEY_Delete
999 #define MP_KEY_KP_Enter GDK_KEY_KP_Enter
1000 #define MP_KEY_Return GDK_KEY_Return
1001 #define MP_KEY_Tab GDK_KEY_Tab
1002 #define MP_KEY_ISO_Left_Tab GDK_KEY_ISO_Left_Tab
1003 #define MP_KEY_Escape GDK_KEY_Escape
1004 #endif /* CONFOPT_GTK == 3 */
1006 static gint
key_press_event(GtkWidget
* widget
, GdkEventKey
* event
,
1008 /* 'key_press_event' handler */
1010 wchar_t *ptr
= NULL
;
1012 gtk_im_context_filter_keypress(im
, event
);
1014 /* set mp.shift_pressed */
1015 if (event
->state
& (GDK_SHIFT_MASK
))
1016 mpdm_hset_s(mp
, L
"shift_pressed", MPDM_I(1));
1018 /* reserve alt for menu mnemonics */
1019 /* if (GDK_MOD1_MASK & event->state)
1022 if (event
->state
& (GDK_CONTROL_MASK
)) {
1023 switch (event
->keyval
) {
1025 ptr
= L
"ctrl-cursor-up";
1028 ptr
= L
"ctrl-cursor-down";
1031 ptr
= L
"ctrl-cursor-left";
1034 ptr
= L
"ctrl-cursor-right";
1037 ptr
= L
"ctrl-page-up";
1040 ptr
= L
"ctrl-page-down";
1049 ptr
= L
"ctrl-space";
1052 ptr
= L
"ctrl-kp-plus";
1054 case MP_KEY_KP_Subtract
:
1055 ptr
= L
"ctrl-kp-minus";
1057 case MP_KEY_KP_Multiply
:
1058 ptr
= L
"ctrl-kp-multiply";
1060 case MP_KEY_KP_Divide
:
1061 ptr
= L
"ctrl-kp-divide";
1099 case MP_KEY_KP_Enter
:
1101 ptr
= L
"ctrl-enter";
1103 case MP_KEY_Cyrillic_ve
:
1106 case MP_KEY_Cyrillic_a
:
1109 case MP_KEY_Cyrillic_tse
:
1112 case MP_KEY_Cyrillic_de
:
1115 case MP_KEY_Cyrillic_ie
:
1118 case MP_KEY_Cyrillic_ef
:
1121 case MP_KEY_Cyrillic_ghe
:
1124 case MP_KEY_Cyrillic_i
:
1127 case MP_KEY_Cyrillic_shorti
:
1130 case MP_KEY_Cyrillic_ka
:
1133 case MP_KEY_Cyrillic_el
:
1136 case MP_KEY_Cyrillic_em
:
1139 case MP_KEY_Cyrillic_en
:
1142 case MP_KEY_Cyrillic_o
:
1145 case MP_KEY_Cyrillic_pe
:
1148 case MP_KEY_Cyrillic_ya
:
1151 case MP_KEY_Cyrillic_er
:
1154 case MP_KEY_Cyrillic_es
:
1157 case MP_KEY_Cyrillic_te
:
1160 case MP_KEY_Cyrillic_softsign
:
1163 case MP_KEY_Cyrillic_yeru
:
1166 case MP_KEY_Cyrillic_ze
:
1169 case MP_KEY_Cyrillic_sha
:
1172 case MP_KEY_Cyrillic_e
:
1175 case MP_KEY_Cyrillic_shcha
:
1178 case MP_KEY_Cyrillic_che
:
1184 char c
= event
->keyval
& 0xdf;
1269 if (event
->state
& (GDK_MOD1_MASK
)) {
1270 switch (event
->keyval
) {
1272 ptr
= L
"alt-cursor-up";
1275 ptr
= L
"alt-cursor-down";
1278 ptr
= L
"alt-cursor-left";
1281 ptr
= L
"alt-cursor-right";
1284 ptr
= L
"alt-page-up";
1287 ptr
= L
"alt-page-down";
1299 ptr
= L
"alt-kp-plus";
1301 case MP_KEY_KP_Subtract
:
1302 ptr
= L
"alt-kp-minus";
1304 case MP_KEY_KP_Multiply
:
1305 ptr
= L
"alt-kp-multiply";
1307 case MP_KEY_KP_Divide
:
1308 ptr
= L
"alt-kp-divide";
1346 case MP_KEY_KP_Enter
:
1350 case MP_KEY_Cyrillic_ve
:
1353 case MP_KEY_Cyrillic_a
:
1356 case MP_KEY_Cyrillic_tse
:
1359 case MP_KEY_Cyrillic_de
:
1362 case MP_KEY_Cyrillic_ie
:
1365 case MP_KEY_Cyrillic_ef
:
1368 case MP_KEY_Cyrillic_ghe
:
1371 case MP_KEY_Cyrillic_i
:
1374 case MP_KEY_Cyrillic_shorti
:
1377 case MP_KEY_Cyrillic_ka
:
1380 case MP_KEY_Cyrillic_el
:
1383 case MP_KEY_Cyrillic_em
:
1386 case MP_KEY_Cyrillic_en
:
1389 case MP_KEY_Cyrillic_o
:
1392 case MP_KEY_Cyrillic_pe
:
1395 case MP_KEY_Cyrillic_ya
:
1398 case MP_KEY_Cyrillic_er
:
1401 case MP_KEY_Cyrillic_es
:
1404 case MP_KEY_Cyrillic_te
:
1407 case MP_KEY_Cyrillic_softsign
:
1410 case MP_KEY_Cyrillic_yeru
:
1413 case MP_KEY_Cyrillic_ze
:
1416 case MP_KEY_Cyrillic_sha
:
1419 case MP_KEY_Cyrillic_e
:
1422 case MP_KEY_Cyrillic_shcha
:
1425 case MP_KEY_Cyrillic_che
:
1431 char c
= event
->keyval
& 0xdf;
1516 switch (event
->keyval
) {
1521 ptr
= L
"cursor-down";
1524 ptr
= L
"cursor-left";
1527 ptr
= L
"cursor-right";
1547 case MP_KEY_KP_Subtract
:
1550 case MP_KEY_KP_Multiply
:
1551 ptr
= L
"kp-multiply";
1553 case MP_KEY_KP_Divide
:
1595 case MP_KEY_BackSpace
:
1601 case MP_KEY_KP_Enter
:
1608 case MP_KEY_ISO_Left_Tab
:
1617 /* if there is a pending char in im_char, use it */
1618 if (ptr
== NULL
&& im_char
[0] != L
'\0')
1621 /* finally process */
1623 mp_process_event(MPDM_S(ptr
));
1625 /* delete the pending char */
1628 if (mp_exit_requested
)
1631 if (mp_keypress_throttle(1))
1632 gtk_drv_paint(mp_active(), 1);
1638 static gint
button_press_event(GtkWidget
* widget
, GdkEventButton
* event
,
1640 /* 'button_press_event' handler (mouse buttons) */
1643 wchar_t *ptr
= NULL
;
1647 /* mouse instant positioning */
1648 x
= ((int) event
->x
) / font_width
;
1649 y
= ((int) event
->y
) / font_height
;
1651 mpdm_hset_s(mp
, L
"mouse_x", MPDM_I(x
));
1652 mpdm_hset_s(mp
, L
"mouse_y", MPDM_I(y
));
1654 switch (event
->button
) {
1656 ptr
= L
"mouse-left-button";
1659 ptr
= L
"mouse-middle-button";
1662 ptr
= L
"mouse-right-button";
1665 ptr
= L
"mouse-wheel-up";
1668 ptr
= L
"mouse-wheel-down";
1673 mp_process_event(MPDM_S(ptr
));
1681 static gint
button_release_event(GtkWidget
* widget
,
1682 GdkEventButton
* event
, gpointer data
)
1683 /* 'button_release_event' handle (mouse buttons) */
1691 static gint
motion_notify_event(GtkWidget
* widget
, GdkEventMotion
* event
,
1693 /* 'motion_notify_event' handler (mouse movement) */
1701 /* mouse dragging */
1702 x
= ((int) event
->x
) / font_width
;
1703 y
= ((int) event
->y
) / font_height
;
1705 if (ox
!= x
&& oy
!= y
) {
1706 mpdm_hset_s(mp
, L
"mouse_to_x", MPDM_I(x
));
1707 mpdm_hset_s(mp
, L
"mouse_to_y", MPDM_I(y
));
1709 mp_process_event(MPDM_LS(L
"mouse-drag"));
1710 gtk_drv_paint(mp_active(), 1);
1718 static void drag_data_received(GtkWidget
* widget
, GdkDragContext
* dc
,
1719 gint x
, gint y
, GtkSelectionData
* data
,
1720 guint info
, guint time
)
1721 /* 'drag_data_received' handler */
1723 printf("drag_data_received (unsupported)\n");
1727 /** clipboard functions **/
1729 static void commit(GtkIMContext
* i
, char *str
, gpointer u
)
1730 /* 'commit' handler */
1734 wstr
= (wchar_t *) g_convert(str
, -1,
1735 "WCHAR_T", "UTF-8", NULL
, NULL
, NULL
);
1744 static void realize(GtkWidget
* widget
)
1745 /* 'realize' handler */
1747 im
= gtk_im_multicontext_new();
1748 g_signal_connect(im
, "commit", G_CALLBACK(commit
), NULL
);
1749 gtk_im_context_set_client_window(im
, gtk_widget_get_window(widget
));
1753 static gint
expose_event(GtkWidget
* widget
, cairo_t
*event
)
1754 /* 'expose_event' handler */
1762 static gint
configure_event(GtkWidget
* widget
, GdkEventConfigure
* event
)
1763 /* 'configure_event' handler */
1765 static GdkEventConfigure o
;
1767 if (memcmp(&o
, event
, sizeof(o
)) == 0)
1770 memcpy(&o
, event
, sizeof(o
));
1772 update_window_size();
1779 static gint
selection_clear_event(GtkWidget
* widget
,
1780 GdkEventSelection
* event
, gpointer data
)
1781 /* 'selection_clear_event' handler */
1789 static void selection_get(GtkWidget
* widget
,
1790 GtkSelectionData
* sel
, guint info
, guint tm
)
1791 /* 'selection_get' handler */
1800 /* gets the clipboard and joins */
1801 d
= mpdm_hget_s(mp
, L
"clipboard");
1803 if (mpdm_size(d
) == 0)
1806 d
= mpdm_ref(mpdm_join_s(d
, L
"\n"));
1808 /* convert to current locale */
1809 ptr
= (unsigned char *) mpdm_wcstombs(d
->data
, &s
);
1811 /* pastes into primary selection */
1812 gtk_selection_data_set(sel
, GDK_SELECTION_TYPE_STRING
, 8, ptr
,
1821 static void selection_received(GtkWidget
* widget
,
1822 GtkSelectionData
* sel
, gpointer data
)
1823 /* 'selection_received' handler */
1827 if (gtk_selection_data_get_data(sel
) != NULL
) {
1829 wchar_t *wptr
= utf8_to_wcs((char *) gtk_selection_data_get_data(sel
));
1833 /* split and set as the clipboard */
1834 mpdm_hset_s(mp
, L
"clipboard", mpdm_split_s(d
, L
"\n"));
1835 mpdm_hset_s(mp
, L
"clipboard_vertical", MPDM_I(0));
1837 /* wait no more for the selection */
1838 wait_for_selection
= 0;
1841 wait_for_selection
= -1;
1845 static mpdm_t
gtk_drv_clip_to_sys(mpdm_t a
, mpdm_t ctxt
)
1846 /* driver-dependent mp to system clipboard */
1848 got_selection
= gtk_selection_owner_set(area
,
1849 GDK_SELECTION_PRIMARY
,
1856 static mpdm_t
gtk_drv_sys_to_clip(mpdm_t a
, mpdm_t ctxt
)
1857 /* driver-dependent system to mp clipboard */
1859 if (!got_selection
) {
1861 char *formats
[] = { "UTF8_STRING", "STRING", NULL
};
1863 for (n
= 0; formats
[n
] != NULL
; n
++) {
1865 /* triggers a selection capture */
1866 if (gtk_selection_convert(area
, GDK_SELECTION_PRIMARY
,
1867 gdk_atom_intern(formats
[n
], FALSE
),
1868 GDK_CURRENT_TIME
)) {
1870 /* processes the pending events
1871 (i.e., the 'selection_received' handler) */
1872 wait_for_selection
= 1;
1874 while (wait_for_selection
== 1)
1875 gtk_main_iteration();
1877 if (!wait_for_selection
)
1887 /** interface functions **/
1889 static void clicked_ok(GtkWidget
* widget
, gpointer data
)
1890 /* 'clicked_on' signal handler (for gtk_drv_form) */
1894 for (n
= 0; n
< mpdm_size(form_args
); n
++) {
1895 GtkWidget
*widget
= form_widgets
[n
];
1896 mpdm_t w
= mpdm_aget(form_args
, n
);
1897 wchar_t *wptr
= mpdm_string(mpdm_hget_s(w
, L
"type"));
1900 /* if there is already a value there, if was
1901 previously set from a callback */
1902 if (mpdm_aget(form_values
, n
) != NULL
)
1905 if (wcscmp(wptr
, L
"text") == 0 || wcscmp(wptr
, L
"password") == 0) {
1907 GtkWidget
*gw
= widget
;
1910 if (wcscmp(wptr
, L
"text") == 0)
1911 gw
= GTK_COMBO(widget
)->entry
;
1914 gtk_editable_get_chars(GTK_EDITABLE(gw
), 0, -1)) != NULL
1915 && (wptr
= utf8_to_wcs(ptr
)) != NULL
) {
1923 /* if it has history, fill it */
1924 if ((h
= mpdm_hget_s(w
, L
"history")) != NULL
&&
1925 v
!= NULL
&& mpdm_cmp_s(v
, L
"") != 0) {
1926 h
= mp_get_history(h
);
1928 if (mpdm_cmp(v
, mpdm_aget(h
, -1)) != 0)
1935 if (wcscmp(wptr
, L
"checkbox") == 0) {
1936 v
= MPDM_I(gtk_toggle_button_get_active
1937 (GTK_TOGGLE_BUTTON(widget
)));
1940 if (wcscmp(wptr
, L
"list") == 0) {
1941 GtkWidget
*list
= gtk_bin_get_child(GTK_BIN(widget
));
1942 GtkTreeSelection
*selection
=
1943 gtk_tree_view_get_selection(GTK_TREE_VIEW(list
));
1945 gtk_tree_selection_get_selected_rows(selection
, NULL
);
1946 GtkTreePath
*path
= selected
->data
;
1948 v
= MPDM_I(gtk_tree_path_get_indices(path
)[0]);
1949 gtk_tree_path_free(path
);
1950 g_list_free(selected
);
1954 mpdm_aset(form_values
, v
, n
);
1959 static gint
timer_callback(gpointer data
)
1961 mpdm_void(mpdm_exec(timer_func
, NULL
, NULL
));
1968 static void build_form_data(mpdm_t widget_list
)
1969 /* builds the necessary information for a list of widgets */
1971 mpdm_unref(form_args
);
1972 form_args
= mpdm_ref(widget_list
);
1974 mpdm_unref(form_values
);
1975 form_values
= widget_list
== NULL
? NULL
:
1976 mpdm_ref(MPDM_A(mpdm_size(form_args
)));
1978 /* resize the widget array */
1979 form_widgets
= (GtkWidget
**) realloc(form_widgets
,
1980 mpdm_size(form_args
) *
1981 sizeof(GtkWidget
*));
1985 /** dialog functions **/
1987 #define DIALOG_BUTTON(l,f) do { GtkWidget * btn; \
1988 ptr = localize(l); btn = gtk_button_new_with_label(ptr); \
1989 g_signal_connect_swapped(G_OBJECT(btn), "clicked", \
1990 G_CALLBACK(f), G_OBJECT(dlg)); \
1991 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), \
1992 btn, TRUE, TRUE, 0); \
1996 static mpdm_t
gtk_drv_alert(mpdm_t a
, mpdm_t ctxt
)
1997 /* alert driver function */
2002 build_form_data(NULL
);
2004 /* 1# arg: prompt */
2005 if ((ptr
= v_to_utf8(mpdm_aget(a
, 0))) == NULL
)
2008 dlg
= gtk_message_dialog_new(GTK_WINDOW(window
), GTK_DIALOG_MODAL
,
2009 GTK_MESSAGE_WARNING
, GTK_BUTTONS_OK
, "%s", ptr
);
2010 gtk_window_set_title(GTK_WINDOW(dlg
), "mp " VERSION
);
2013 gtk_dialog_run(GTK_DIALOG(dlg
));
2014 gtk_widget_destroy(dlg
);
2020 static mpdm_t
gtk_drv_confirm(mpdm_t a
, mpdm_t ctxt
)
2021 /* confirm driver function */
2027 build_form_data(NULL
);
2029 /* 1# arg: prompt */
2030 if ((ptr
= v_to_utf8(mpdm_aget(a
, 0))) == NULL
)
2033 dlg
= gtk_message_dialog_new(GTK_WINDOW(window
), GTK_DIALOG_MODAL
,
2034 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
,
2036 gtk_window_set_title(GTK_WINDOW(dlg
), "mp " VERSION
);
2039 gtk_dialog_add_button(GTK_DIALOG(dlg
), GTK_STOCK_YES
, 1);
2040 gtk_dialog_add_button(GTK_DIALOG(dlg
), GTK_STOCK_NO
, 2);
2041 gtk_dialog_add_button(GTK_DIALOG(dlg
), GTK_STOCK_CANCEL
, 0);
2043 response
= gtk_dialog_run(GTK_DIALOG(dlg
));
2044 gtk_widget_destroy(dlg
);
2046 if (response
== GTK_RESPONSE_DELETE_EVENT
)
2049 return MPDM_I(response
);
2053 static mpdm_t
gtk_drv_form(mpdm_t a
, mpdm_t ctxt
)
2054 /* 'form' driver function */
2058 GtkWidget
*content_area
;
2062 /* first argument: list of widgets */
2063 build_form_data(mpdm_aget(a
, 0));
2065 dlg
= gtk_dialog_new_with_buttons("mp " VERSION
, GTK_WINDOW(window
),
2068 GTK_RESPONSE_CANCEL
, GTK_STOCK_OK
,
2069 GTK_RESPONSE_OK
, NULL
);
2070 gtk_dialog_set_default_response(GTK_DIALOG(dlg
), GTK_RESPONSE_OK
);
2071 gtk_container_set_border_width(GTK_CONTAINER(dlg
), 5);
2073 content_area
= gtk_dialog_get_content_area(GTK_DIALOG(dlg
));
2074 gtk_box_set_spacing(GTK_BOX(content_area
), 2);
2076 table
= gtk_table_new(mpdm_size(a
), 2, FALSE
);
2077 gtk_container_set_border_width(GTK_CONTAINER(table
), 5);
2078 gtk_table_set_col_spacings(GTK_TABLE(table
), 12);
2079 gtk_table_set_row_spacings(GTK_TABLE(table
), 6);
2081 for (n
= 0; n
< mpdm_size(form_args
); n
++) {
2082 mpdm_t w
= mpdm_aget(form_args
, n
);
2083 GtkWidget
*widget
= NULL
;
2089 type
= mpdm_string(mpdm_hget_s(w
, L
"type"));
2091 if ((t
= mpdm_hget_s(w
, L
"label")) != NULL
) {
2094 if ((ptr
= v_to_utf8(mpdm_gettext(t
))) != NULL
) {
2095 label
= gtk_label_new(ptr
);
2096 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
2098 gtk_table_attach_defaults(GTK_TABLE(table
),
2099 label
, 0, wcscmp(type
,
2101 0 ? 2 : 1, n
, n
+ 1);
2109 t
= mpdm_hget_s(w
, L
"value");
2111 if (wcscmp(type
, L
"text") == 0) {
2112 GList
*combo_items
= NULL
;
2115 widget
= gtk_combo_new();
2116 gtk_widget_set_size_request(widget
, 300, -1);
2117 gtk_combo_set_use_arrows_always(GTK_COMBO(widget
), TRUE
);
2118 gtk_combo_set_case_sensitive(GTK_COMBO(widget
), TRUE
);
2119 gtk_entry_set_activates_default(GTK_ENTRY
2120 (GTK_COMBO(widget
)->entry
),
2123 if ((h
= mpdm_hget_s(w
, L
"history")) != NULL
) {
2126 /* has history; fill it */
2127 h
= mp_get_history(h
);
2129 for (i
= 0; i
< mpdm_size(h
); i
++) {
2130 ptr
= v_to_utf8(mpdm_aget(h
, i
));
2132 combo_items
= g_list_prepend(combo_items
, ptr
);
2139 combo_items
= g_list_prepend(combo_items
, ptr
);
2142 gtk_combo_set_popdown_strings(GTK_COMBO(widget
), combo_items
);
2143 g_list_free(combo_items
);
2146 if (wcscmp(type
, L
"password") == 0) {
2147 widget
= gtk_entry_new();
2148 gtk_widget_set_size_request(widget
, 300, -1);
2149 gtk_entry_set_visibility(GTK_ENTRY(widget
), FALSE
);
2152 if (wcscmp(type
, L
"checkbox") == 0) {
2153 widget
= gtk_check_button_new();
2155 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget
),
2156 mpdm_ival(t
) ? TRUE
: FALSE
);
2159 if (wcscmp(type
, L
"list") == 0) {
2161 GtkListStore
*list_store
;
2162 GtkCellRenderer
*renderer
;
2163 GtkTreeViewColumn
*column
;
2168 if ((i
= 450 / mpdm_size(form_args
)) < 100)
2171 widget
= gtk_scrolled_window_new(NULL
, NULL
);
2172 gtk_widget_set_size_request(widget
, 500, i
);
2173 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget
),
2175 GTK_POLICY_AUTOMATIC
);
2176 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW
2177 (widget
), GTK_SHADOW_IN
);
2179 list_store
= gtk_list_store_new(1, G_TYPE_STRING
);
2181 gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store
));
2182 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list
), FALSE
);
2183 renderer
= gtk_cell_renderer_text_new();
2184 column
= gtk_tree_view_column_new_with_attributes("", renderer
,
2187 gtk_tree_view_append_column(GTK_TREE_VIEW(list
), column
);
2188 gtk_container_add(GTK_CONTAINER(widget
), list
);
2190 l
= mpdm_hget_s(w
, L
"list");
2192 for (i
= 0; i
< mpdm_size(l
); i
++) {
2193 if ((ptr
= v_to_utf8(mpdm_aget(l
, i
))) != NULL
) {
2195 gtk_list_store_append(list_store
, &iter
);
2196 gtk_list_store_set(list_store
, &iter
, 0, ptr
, -1);
2201 /* initial position */
2204 path
= gtk_tree_path_new_from_indices(i
, -1);
2205 gtk_tree_view_set_cursor(GTK_TREE_VIEW(list
), path
, NULL
,
2207 gtk_tree_path_free(path
);
2209 g_signal_connect_swapped(G_OBJECT(list
), "row-activated",
2211 (gtk_window_activate_default
), dlg
);
2214 if (widget
!= NULL
) {
2215 form_widgets
[n
] = widget
;
2216 gtk_table_attach_defaults(GTK_TABLE(table
),
2217 widget
, col
, 2, n
, n
+ 1);
2221 gtk_widget_show_all(table
);
2223 gtk_box_pack_start(GTK_BOX(content_area
), table
, TRUE
, TRUE
, 0);
2225 if (gtk_dialog_run(GTK_DIALOG(dlg
)) == GTK_RESPONSE_OK
) {
2226 clicked_ok(NULL
, NULL
);
2229 gtk_widget_destroy(dlg
);
2235 static mpdm_t
run_filechooser(mpdm_t a
, gboolean save
)
2236 /* openfile driver function */
2243 /* 1# arg: prompt */
2244 if ((ptr
= v_to_utf8(mpdm_aget(a
, 0))) == NULL
)
2248 dlg
= gtk_file_chooser_dialog_new(ptr
, GTK_WINDOW(window
),
2249 GTK_FILE_CHOOSER_ACTION_OPEN
,
2251 GTK_RESPONSE_CANCEL
,
2252 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
2256 dlg
= gtk_file_chooser_dialog_new(ptr
, GTK_WINDOW(window
),
2257 GTK_FILE_CHOOSER_ACTION_SAVE
,
2259 GTK_STOCK_CANCEL
, GTK_STOCK_OK
,
2260 GTK_RESPONSE_OK
, NULL
);
2261 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER
2266 build_form_data(NULL
);
2268 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg
), TRUE
);
2269 response
= gtk_dialog_run(GTK_DIALOG(dlg
));
2271 if (response
== GTK_RESPONSE_OK
) {
2276 filename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg
));
2277 utf8name
= g_filename_to_utf8(filename
, -1, NULL
, NULL
, NULL
);
2279 wfilename
= utf8_to_wcs(utf8name
);
2281 ret
= MPDM_S(wfilename
);
2284 gtk_widget_destroy(dlg
);
2290 static mpdm_t
gtk_drv_openfile(mpdm_t a
, mpdm_t ctxt
)
2291 /* openfile driver function */
2293 return run_filechooser(a
, FALSE
);
2297 static mpdm_t
gtk_drv_savefile(mpdm_t a
, mpdm_t ctxt
)
2298 /* savefile driver function */
2300 return run_filechooser(a
, TRUE
);
2304 static mpdm_t
gtk_drv_update_ui(mpdm_t a
, mpdm_t ctxt
)
2316 static mpdm_t
gtk_drv_timer(mpdm_t a
, mpdm_t ctxt
)
2318 static guint prev
= 0;
2319 int msecs
= mpdm_ival(mpdm_aget(a
, 0));
2320 mpdm_t func
= mpdm_aget(a
, 1);
2322 /* previously defined one? remove */
2323 if (timer_func
!= NULL
)
2324 g_source_remove(prev
);
2326 /* if msecs and func are set, program timer */
2327 if (msecs
> 0 && func
!= NULL
)
2328 prev
= g_timeout_add(msecs
, timer_callback
, NULL
);
2331 mpdm_unref(timer_func
);
2338 static mpdm_t
gtk_drv_busy(mpdm_t a
, mpdm_t ctxt
)
2340 int onoff
= mpdm_ival(mpdm_aget(a
, 0));
2342 gdk_window_set_cursor(gtk_widget_get_window(window
),
2343 gdk_cursor_new(onoff
? GDK_WATCH
:
2346 while (gtk_events_pending())
2347 gtk_main_iteration();
2353 static mpdm_t
gtk_drv_main_loop(mpdm_t a
, mpdm_t ctxt
)
2356 if (!mp_exit_requested
) {
2357 gtk_drv_paint(mp_active(), 0);
2366 static mpdm_t
gtk_drv_shutdown(mpdm_t a
, mpdm_t ctxt
)
2371 if ((v
= mpdm_hget_s(mp
, L
"exit_message")) != NULL
) {
2372 mpdm_write_wcs(stdout
, mpdm_string(v
));
2380 static void register_functions(void)
2384 drv
= mpdm_hget_s(mp
, L
"drv");
2385 mpdm_hset_s(drv
, L
"main_loop", MPDM_X(gtk_drv_main_loop
));
2386 mpdm_hset_s(drv
, L
"shutdown", MPDM_X(gtk_drv_shutdown
));
2387 mpdm_hset_s(drv
, L
"clip_to_sys", MPDM_X(gtk_drv_clip_to_sys
));
2388 mpdm_hset_s(drv
, L
"sys_to_clip", MPDM_X(gtk_drv_sys_to_clip
));
2389 mpdm_hset_s(drv
, L
"update_ui", MPDM_X(gtk_drv_update_ui
));
2390 mpdm_hset_s(drv
, L
"timer", MPDM_X(gtk_drv_timer
));
2391 mpdm_hset_s(drv
, L
"busy", MPDM_X(gtk_drv_busy
));
2392 mpdm_hset_s(drv
, L
"alert", MPDM_X(gtk_drv_alert
));
2393 mpdm_hset_s(drv
, L
"confirm", MPDM_X(gtk_drv_confirm
));
2394 mpdm_hset_s(drv
, L
"openfile", MPDM_X(gtk_drv_openfile
));
2395 mpdm_hset_s(drv
, L
"savefile", MPDM_X(gtk_drv_savefile
));
2396 mpdm_hset_s(drv
, L
"form", MPDM_X(gtk_drv_form
));
2400 static mpdm_t
gtk_drv_startup(mpdm_t a
, mpdm_t ctxt
)
2401 /* driver initialization */
2410 GtkTargetEntry targets
[] = {
2411 {"text/plain", 0, 0},
2412 {"text/uri-list", 0, 1}
2415 register_functions();
2417 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
2419 gtk_window_set_title(GTK_WINDOW(window
), "mp " VERSION
);
2421 /* get real screen and pick a usable size for the main area */
2422 screen
= gtk_window_get_screen(GTK_WINDOW(window
));
2423 if (gdk_screen_get_n_monitors(screen
) > 1) {
2424 GdkRectangle monitor_one_size
;
2425 gdk_screen_get_monitor_geometry(screen
, 0, &monitor_one_size
);
2427 w
= (monitor_one_size
.width
* 3) / 4;
2428 h
= (monitor_one_size
.height
* 2) / 3;
2430 w
= (gdk_screen_get_width(screen
) * 3) / 4;
2431 h
= (gdk_screen_get_height(screen
) * 2) / 3;
2434 g_signal_connect(G_OBJECT(window
), "delete_event",
2435 G_CALLBACK(delete_event
), NULL
);
2437 g_signal_connect(G_OBJECT(window
), "destroy",
2438 G_CALLBACK(destroy
), NULL
);
2441 file_tabs
= gtk_notebook_new();
2442 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(file_tabs
), GTK_POS_TOP
);
2443 GTK_WIDGET_UNSET_FLAGS(file_tabs
, GTK_CAN_FOCUS
);
2444 gtk_notebook_set_scrollable(GTK_NOTEBOOK(file_tabs
), 1);
2446 vbox
= gtk_vbox_new(FALSE
, 2);
2447 gtk_container_add(GTK_CONTAINER(window
), vbox
);
2451 hbox
= gtk_hbox_new(FALSE
, 0);
2452 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
2453 gtk_box_pack_start(GTK_BOX(hbox
), menu_bar
, FALSE
, FALSE
, 0);
2454 gtk_box_pack_start(GTK_BOX(hbox
), file_tabs
, TRUE
, TRUE
, 0);
2456 gtk_notebook_popup_enable(GTK_NOTEBOOK(file_tabs
));
2458 /* horizontal box holding the text and the scrollbar */
2459 hbox
= gtk_hbox_new(FALSE
, 2);
2460 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, TRUE
, TRUE
, 0);
2462 /* the Minimum Profit area */
2463 area
= gtk_drawing_area_new();
2464 gtk_box_pack_start(GTK_BOX(hbox
), area
, TRUE
, TRUE
, 0);
2465 gtk_widget_set_size_request(GTK_WIDGET(area
), w
, h
);
2466 gtk_widget_set_events(GTK_WIDGET(area
), GDK_BUTTON_PRESS_MASK
|
2467 GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK
2468 | GDK_LEAVE_NOTIFY_MASK
);
2470 gtk_widget_set_double_buffered(area
, FALSE
);
2472 g_signal_connect(G_OBJECT(area
), "configure_event",
2473 G_CALLBACK(configure_event
), NULL
);
2475 g_signal_connect(G_OBJECT(area
), "expose_event",
2476 G_CALLBACK(expose_event
), NULL
);
2478 g_signal_connect(G_OBJECT(area
), "realize", G_CALLBACK(realize
), NULL
);
2480 g_signal_connect(G_OBJECT(window
), "key_press_event",
2481 G_CALLBACK(key_press_event
), NULL
);
2483 g_signal_connect(G_OBJECT(window
), "key_release_event",
2484 G_CALLBACK(key_release_event
), NULL
);
2486 g_signal_connect(G_OBJECT(area
), "button_press_event",
2487 G_CALLBACK(button_press_event
), NULL
);
2489 g_signal_connect(G_OBJECT(area
), "button_release_event",
2490 G_CALLBACK(button_release_event
), NULL
);
2492 g_signal_connect(G_OBJECT(area
), "motion_notify_event",
2493 G_CALLBACK(motion_notify_event
), NULL
);
2495 g_signal_connect(G_OBJECT(area
), "selection_clear_event",
2496 G_CALLBACK(selection_clear_event
), NULL
);
2498 g_signal_connect(G_OBJECT(area
), "selection_get",
2499 G_CALLBACK(selection_get
), NULL
);
2501 g_signal_connect(G_OBJECT(area
), "selection_received",
2502 G_CALLBACK(selection_received
), NULL
);
2504 g_signal_connect(G_OBJECT(area
), "scroll_event",
2505 G_CALLBACK(scroll_event
), NULL
);
2507 gtk_drag_dest_set(area
, GTK_DEST_DEFAULT_ALL
, targets
,
2508 sizeof(targets
) / sizeof(GtkTargetEntry
),
2510 g_signal_connect(G_OBJECT(area
), "drag_data_received",
2511 G_CALLBACK(drag_data_received
), NULL
);
2513 gtk_selection_add_target(area
, GDK_SELECTION_PRIMARY
,
2514 GDK_SELECTION_TYPE_STRING
, 1);
2516 g_signal_connect(G_OBJECT(file_tabs
), "switch_page",
2517 G_CALLBACK(switch_page
), NULL
);
2520 scrollbar
= gtk_vscrollbar_new(NULL
);
2521 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, FALSE
, 0);
2523 g_signal_connect(G_OBJECT
2524 (gtk_range_get_adjustment(GTK_RANGE(scrollbar
))),
2525 "value_changed", G_CALLBACK(value_changed
), NULL
);
2527 /* the status bar */
2528 status
= gtk_label_new("mp " VERSION
);
2529 gtk_box_pack_start(GTK_BOX(vbox
), status
, FALSE
, FALSE
, 0);
2530 gtk_misc_set_alignment(GTK_MISC(status
), 0, 0.5);
2531 gtk_label_set_justify(GTK_LABEL(status
), GTK_JUSTIFY_LEFT
);
2533 gtk_widget_show_all(window
);
2535 /* set application icon */
2536 pixmap
= gdk_pixmap_create_from_xpm_d(window
->window
,
2537 &mask
, NULL
, mp_xpm
);
2538 gdk_window_set_icon(window
->window
, NULL
, pixmap
, mask
);
2542 if ((v
= mpdm_hget_s(mp
, L
"config")) != NULL
&&
2543 mpdm_ival(mpdm_hget_s(v
, L
"maximize")) > 0)
2550 int gtk_drv_detect(int *argc
, char ***argv
)
2555 for (n
= 0; n
< *argc
; n
++) {
2556 if (strcmp(argv
[0][n
], "-txt") == 0 ||
2557 strcmp(argv
[0][n
], "-h") == 0)
2561 if (!gtk_init_check(argc
, argv
))
2564 drv
= mpdm_hget_s(mp
, L
"drv");
2565 mpdm_hset_s(drv
, L
"id", MPDM_LS(L
"gtk"));
2566 mpdm_hset_s(drv
, L
"startup", MPDM_X(gtk_drv_startup
));
2571 #endif /* CONFOPT_GTK */