36 |
#include "coding.h" |
#include "coding.h" |
37 |
#include <gdk/gdkkeysyms.h> |
#include <gdk/gdkkeysyms.h> |
38 |
|
|
39 |
|
|
40 |
#define FRAME_TOTAL_PIXEL_HEIGHT(f) \ |
#define FRAME_TOTAL_PIXEL_HEIGHT(f) \ |
41 |
(FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f)) |
(FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f)) |
42 |
|
|
43 |
|
|
44 |
|
/*********************************************************************** |
45 |
|
Display handling functions |
46 |
|
***********************************************************************/ |
47 |
|
|
48 |
|
#ifdef HAVE_GTK_MULTIDISPLAY |
49 |
|
|
50 |
|
/* Return the GdkDisplay that corresponds to the X display DPY. */ |
51 |
|
static GdkDisplay * |
52 |
|
xg_get_gdk_display (dpy) |
53 |
|
Display *dpy; |
54 |
|
{ |
55 |
|
return gdk_x11_lookup_xdisplay (dpy); |
56 |
|
} |
57 |
|
|
58 |
|
/* When the GTK widget W is to be created on a display for F that |
59 |
|
is not the default display, set the display for W. |
60 |
|
W can be a GtkMenu or a GtkWindow widget. */ |
61 |
|
static void |
62 |
|
xg_set_screen (w, f) |
63 |
|
GtkWidget *w; |
64 |
|
FRAME_PTR f; |
65 |
|
{ |
66 |
|
if (FRAME_X_DISPLAY (f) != GDK_DISPLAY ()) |
67 |
|
{ |
68 |
|
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f)); |
69 |
|
GdkScreen *gscreen = gdk_display_get_default_screen (gdpy); |
70 |
|
|
71 |
|
if (GTK_IS_MENU (w)) |
72 |
|
gtk_menu_set_screen (GTK_MENU (w), gscreen); |
73 |
|
else |
74 |
|
gtk_window_set_screen (GTK_WINDOW (w), gscreen); |
75 |
|
} |
76 |
|
} |
77 |
|
|
78 |
|
|
79 |
|
#else /* not HAVE_GTK_MULTIDISPLAY */ |
80 |
|
|
81 |
|
/* Make some defines so we can use the GTK 2.2 functions when |
82 |
|
compiling with GTK 2.0. */ |
83 |
|
#define xg_set_screen(w, f) |
84 |
|
#define gdk_xid_table_lookup_for_display(dpy, w) gdk_xid_table_lookup (w) |
85 |
|
#define gdk_pixmap_foreign_new_for_display(dpy, p) gdk_pixmap_foreign_new (p) |
86 |
|
#define gdk_cursor_new_for_display(dpy, c) gdk_cursor_new (c) |
87 |
|
#define gdk_x11_lookup_xdisplay(dpy) 0 |
88 |
|
#define GdkDisplay void |
89 |
|
|
90 |
|
#endif /* not HAVE_GTK_MULTIDISPLAY */ |
91 |
|
|
92 |
|
/* Open a display named by DISPLAY_NAME. The display is returned in *DPY. |
93 |
|
*DPY is set to NULL if the display can't be opened. |
94 |
|
|
95 |
|
Returns non-zero if display could be opened, zero if display could not |
96 |
|
be opened, and less than zero if the GTK version doesn't support |
97 |
|
multipe displays. */ |
98 |
|
int |
99 |
|
xg_display_open (display_name, dpy) |
100 |
|
char *display_name; |
101 |
|
Display **dpy; |
102 |
|
{ |
103 |
|
#ifdef HAVE_GTK_MULTIDISPLAY |
104 |
|
GdkDisplay *gdpy; |
105 |
|
|
106 |
|
gdpy = gdk_display_open (display_name); |
107 |
|
*dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL; |
108 |
|
|
109 |
|
return gdpy != NULL; |
110 |
|
|
111 |
|
#else /* not HAVE_GTK_MULTIDISPLAY */ |
112 |
|
|
113 |
|
return -1; |
114 |
|
#endif /* not HAVE_GTK_MULTIDISPLAY */ |
115 |
|
} |
116 |
|
|
117 |
|
|
118 |
|
void |
119 |
|
xg_display_close (Display *dpy) |
120 |
|
{ |
121 |
|
#ifdef HAVE_GTK_MULTIDISPLAY |
122 |
|
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy); |
123 |
|
|
124 |
|
/* GTK 2.2 has a bug that makes gdk_display_close crash (bug |
125 |
|
http://bugzilla.gnome.org/show_bug.cgi?id=85715). This way |
126 |
|
we can continue running, but there will be memory leaks. */ |
127 |
|
|
128 |
|
#if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4 |
129 |
|
|
130 |
|
/* If this is the default display, we must change it before calling |
131 |
|
dispose, otherwise it will crash. */ |
132 |
|
if (gdk_display_get_default () == gdpy) |
133 |
|
{ |
134 |
|
struct x_display_info *dpyinfo; |
135 |
|
Display *new_dpy = 0; |
136 |
|
GdkDisplay *gdpy_new; |
137 |
|
|
138 |
|
/* Find another display. */ |
139 |
|
for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) |
140 |
|
if (dpyinfo->display != dpy) |
141 |
|
{ |
142 |
|
new_dpy = dpyinfo->display; |
143 |
|
break; |
144 |
|
} |
145 |
|
|
146 |
|
if (! new_dpy) return; /* Emacs will exit anyway. */ |
147 |
|
|
148 |
|
gdpy_new = gdk_x11_lookup_xdisplay (new_dpy); |
149 |
|
gdk_display_manager_set_default_display (gdk_display_manager_get (), |
150 |
|
gdpy_new); |
151 |
|
} |
152 |
|
|
153 |
|
g_object_run_dispose (G_OBJECT (gdpy)); |
154 |
|
|
155 |
|
#else |
156 |
|
/* I hope this will be fixed in GTK 2.4. It is what bug 85715 says. */ |
157 |
|
gdk_display_close (gdpy); |
158 |
|
#endif |
159 |
|
#endif /* HAVE_GTK_MULTIDISPLAY */ |
160 |
|
} |
161 |
|
|
162 |
|
|
163 |
/*********************************************************************** |
/*********************************************************************** |
167 |
NULL if no timer is started. */ |
NULL if no timer is started. */ |
168 |
static struct atimer *xg_timer; |
static struct atimer *xg_timer; |
169 |
|
|
|
/* The cursor used for scroll bars and popup menus. |
|
|
We only have one cursor for all scroll bars and all popup menus. */ |
|
|
static GdkCursor *xg_left_ptr_cursor; |
|
|
|
|
170 |
|
|
171 |
/* The next two variables and functions are taken from lwlib. */ |
/* The next two variables and functions are taken from lwlib. */ |
172 |
static widget_value *widget_value_free_list; |
static widget_value *widget_value_free_list; |
218 |
} |
} |
219 |
} |
} |
220 |
|
|
|
/* Set *CURSOR on W and all widgets W contain. We must do like this |
|
|
for scroll bars and menu because they create widgets internally, |
|
|
and it is those widgets that are visible. |
|
221 |
|
|
222 |
If *CURSOR is NULL, create a GDK_LEFT_PTR cursor and set *CURSOR to |
/* Create and return the cursor to be used for popup menus and |
223 |
the created cursor. */ |
scroll bars on display DPY. */ |
224 |
void |
GdkCursor * |
225 |
|
xg_create_default_cursor (dpy) |
226 |
|
Display *dpy; |
227 |
|
{ |
228 |
|
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy); |
229 |
|
return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR); |
230 |
|
} |
231 |
|
|
232 |
|
/* For the image defined in IMG, make and return a GdkPixmap for |
233 |
|
the pixmap in *GPIX, and a GdkBitmap for the mask in *GMASK. |
234 |
|
If IMG has no mask, *GMASK is set to NULL. |
235 |
|
The image is defined on the display where frame F is. */ |
236 |
|
static void |
237 |
|
xg_get_gdk_pixmap_and_mask (f, img, gpix, gmask) |
238 |
|
FRAME_PTR f; |
239 |
|
struct image *img; |
240 |
|
GdkPixmap **gpix; |
241 |
|
GdkBitmap **gmask; |
242 |
|
{ |
243 |
|
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f)); |
244 |
|
|
245 |
|
*gpix = gdk_pixmap_foreign_new_for_display (gdpy, img->pixmap); |
246 |
|
*gmask = img->mask ? |
247 |
|
(GdkBitmap*) gdk_pixmap_foreign_new_for_display (gdpy, img->mask) |
248 |
|
: 0; |
249 |
|
} |
250 |
|
|
251 |
|
|
252 |
|
/* Set CURSOR on W and all widgets W contain. We must do like this |
253 |
|
for scroll bars and menu because they create widgets internally, |
254 |
|
and it is those widgets that are visible. */ |
255 |
|
static void |
256 |
xg_set_cursor (w, cursor) |
xg_set_cursor (w, cursor) |
257 |
GtkWidget *w; |
GtkWidget *w; |
258 |
GdkCursor **cursor; |
GdkCursor *cursor; |
259 |
{ |
{ |
260 |
GList *children = gdk_window_peek_children (w->window); |
GList *children = gdk_window_peek_children (w->window); |
261 |
|
|
262 |
/* Create the cursor unless already created. */ |
gdk_window_set_cursor (w->window, cursor); |
|
if (! *cursor) |
|
|
*cursor = gdk_cursor_new (GDK_LEFT_PTR); |
|
|
|
|
|
gdk_window_set_cursor (w->window, *cursor); |
|
263 |
|
|
264 |
/* The scroll bar widget has more than one GDK window (had to look at |
/* The scroll bar widget has more than one GDK window (had to look at |
265 |
the source to figure this out), and there is no way to set cursor |
the source to figure this out), and there is no way to set cursor |
267 |
Ditto for menus. */ |
Ditto for menus. */ |
268 |
|
|
269 |
for ( ; children; children = g_list_next (children)) |
for ( ; children; children = g_list_next (children)) |
270 |
gdk_window_set_cursor (GDK_WINDOW (children->data), *cursor); |
gdk_window_set_cursor (GDK_WINDOW (children->data), cursor); |
271 |
} |
} |
272 |
|
|
273 |
/* Timer function called when a timeout occurs for xg_timer. |
/* Timer function called when a timeout occurs for xg_timer. |
520 |
cancel_mouse_face (f); |
cancel_mouse_face (f); |
521 |
} |
} |
522 |
|
|
523 |
/* Convert an X Window WSESC to its corresponding GtkWidget. |
/* Convert an X Window WSESC on display DPY to its corresponding GtkWidget. |
524 |
Must be done like this, because GtkWidget:s can have "hidden" |
Must be done like this, because GtkWidget:s can have "hidden" |
525 |
X Window that aren't accessible. |
X Window that aren't accessible. |
526 |
|
|
527 |
Return 0 if no widget match WDESC. */ |
Return 0 if no widget match WDESC. */ |
528 |
GtkWidget * |
GtkWidget * |
529 |
xg_win_to_widget (wdesc) |
xg_win_to_widget (dpy, wdesc) |
530 |
|
Display *dpy; |
531 |
Window wdesc; |
Window wdesc; |
532 |
{ |
{ |
533 |
gpointer gdkwin; |
gpointer gdkwin; |
534 |
GtkWidget *gwdesc = 0; |
GtkWidget *gwdesc = 0; |
535 |
|
|
536 |
BLOCK_INPUT; |
BLOCK_INPUT; |
537 |
gdkwin = gdk_xid_table_lookup (wdesc); |
|
538 |
|
gdkwin = gdk_xid_table_lookup_for_display (gdk_x11_lookup_xdisplay (dpy), |
539 |
|
wdesc); |
540 |
if (gdkwin) |
if (gdkwin) |
541 |
{ |
{ |
542 |
GdkEvent event; |
GdkEvent event; |
571 |
Return TRUE to tell GTK that this expose event has been fully handeled |
Return TRUE to tell GTK that this expose event has been fully handeled |
572 |
and that GTK shall do nothing more with it. */ |
and that GTK shall do nothing more with it. */ |
573 |
static gboolean |
static gboolean |
574 |
xg_fixed_handle_expose(GtkWidget *widget, |
xg_fixed_handle_expose (GtkWidget *widget, |
575 |
GdkEventExpose *event, |
GdkEventExpose *event, |
576 |
gpointer user_data) |
gpointer user_data) |
577 |
{ |
{ |
578 |
GList *iter; |
GList *iter; |
579 |
|
|
625 |
BLOCK_INPUT; |
BLOCK_INPUT; |
626 |
|
|
627 |
wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
628 |
|
xg_set_screen (wtop, f); |
629 |
|
|
630 |
wvbox = gtk_vbox_new (FALSE, 0); |
wvbox = gtk_vbox_new (FALSE, 0); |
631 |
wfixed = gtk_fixed_new (); /* Must have this to place scroll bars */ |
wfixed = gtk_fixed_new (); /* Must have this to place scroll bars */ |
632 |
|
|
656 |
|
|
657 |
gtk_fixed_set_has_window (GTK_FIXED (wfixed), TRUE); |
gtk_fixed_set_has_window (GTK_FIXED (wfixed), TRUE); |
658 |
|
|
659 |
gtk_widget_set_size_request (wfixed, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); |
gtk_widget_set_size_request (wfixed, FRAME_PIXEL_WIDTH (f), |
660 |
|
FRAME_PIXEL_HEIGHT (f)); |
661 |
|
|
662 |
gtk_container_add (GTK_CONTAINER (wtop), wvbox); |
gtk_container_add (GTK_CONTAINER (wtop), wvbox); |
663 |
gtk_box_pack_end (GTK_BOX (wvbox), wfixed, TRUE, TRUE, 0); |
gtk_box_pack_end (GTK_BOX (wvbox), wfixed, TRUE, TRUE, 0); |
1108 |
filewin = gtk_file_selection_new (prompt); |
filewin = gtk_file_selection_new (prompt); |
1109 |
filesel = GTK_FILE_SELECTION (filewin); |
filesel = GTK_FILE_SELECTION (filewin); |
1110 |
|
|
1111 |
|
xg_set_screen (filewin, f); |
1112 |
|
|
1113 |
gtk_widget_set_name (filewin, "emacs-filedialog"); |
gtk_widget_set_name (filewin, "emacs-filedialog"); |
1114 |
|
|
1115 |
gtk_window_set_transient_for (GTK_WINDOW (filewin), |
gtk_window_set_transient_for (GTK_WINDOW (filewin), |
1647 |
|
|
1648 |
if (! topmenu) |
if (! topmenu) |
1649 |
{ |
{ |
1650 |
if (! menu_bar_p) wmenu = gtk_menu_new (); |
if (! menu_bar_p) |
1651 |
|
{ |
1652 |
|
wmenu = gtk_menu_new (); |
1653 |
|
xg_set_screen (wmenu, f); |
1654 |
|
} |
1655 |
else wmenu = gtk_menu_bar_new (); |
else wmenu = gtk_menu_bar_new (); |
1656 |
|
|
1657 |
/* Put cl_data on the top menu for easier access. */ |
/* Put cl_data on the top menu for easier access. */ |
1769 |
if (strcmp (type, "dialog") == 0) |
if (strcmp (type, "dialog") == 0) |
1770 |
{ |
{ |
1771 |
w = create_dialog (val, select_cb, deactivate_cb); |
w = create_dialog (val, select_cb, deactivate_cb); |
1772 |
|
xg_set_screen (w, f); |
1773 |
gtk_window_set_transient_for (GTK_WINDOW (w), |
gtk_window_set_transient_for (GTK_WINDOW (w), |
1774 |
GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); |
GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); |
1775 |
gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE); |
gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE); |
1776 |
|
gtk_widget_set_name (w, "emacs-dialog"); |
|
if (w) |
|
|
gtk_widget_set_name (w, "emacs-dialog"); |
|
1777 |
} |
} |
1778 |
else if (menu_bar_p || pop_up_p) |
else if (menu_bar_p || pop_up_p) |
1779 |
{ |
{ |
1795 |
{ |
{ |
1796 |
/* Must realize so the GdkWindow inside the widget is created. */ |
/* Must realize so the GdkWindow inside the widget is created. */ |
1797 |
gtk_widget_realize (w); |
gtk_widget_realize (w); |
1798 |
xg_set_cursor (w, &xg_left_ptr_cursor); |
xg_set_cursor (w, FRAME_X_DISPLAY_INFO (f)->xg_cursor); |
1799 |
} |
} |
1800 |
} |
} |
1801 |
else |
else |
2411 |
a new menu bar item, it has no sub menu yet. So we set the |
a new menu bar item, it has no sub menu yet. So we set the |
2412 |
newly created sub menu under witem. */ |
newly created sub menu under witem. */ |
2413 |
if (newsub != sub) |
if (newsub != sub) |
2414 |
gtk_menu_item_set_submenu (witem, newsub); |
{ |
2415 |
|
xg_set_screen (newsub, f); |
2416 |
|
gtk_menu_item_set_submenu (witem, newsub); |
2417 |
|
} |
2418 |
} |
} |
2419 |
} |
} |
2420 |
|
|
2570 |
return 0; |
return 0; |
2571 |
} |
} |
2572 |
|
|
2573 |
/* Return the scrollbar id for X Window WID. |
/* Return the scrollbar id for X Window WID on display DPY. |
2574 |
Return -1 if WID not in id_to_widget. */ |
Return -1 if WID not in id_to_widget. */ |
2575 |
int |
int |
2576 |
xg_get_scroll_id_for_window (wid) |
xg_get_scroll_id_for_window (dpy, wid) |
2577 |
|
Display *dpy; |
2578 |
Window wid; |
Window wid; |
2579 |
{ |
{ |
2580 |
int idx; |
int idx; |
2581 |
GtkWidget *w; |
GtkWidget *w; |
2582 |
|
|
2583 |
w = xg_win_to_widget (wid); |
w = xg_win_to_widget (dpy, wid); |
2584 |
|
|
2585 |
if (w) |
if (w) |
2586 |
{ |
{ |
2687 |
wscroll, -1, -1); |
wscroll, -1, -1); |
2688 |
|
|
2689 |
/* Set the cursor to an arrow. */ |
/* Set the cursor to an arrow. */ |
2690 |
xg_set_cursor (wscroll, &xg_left_ptr_cursor); |
xg_set_cursor (wscroll, FRAME_X_DISPLAY_INFO (f)->xg_cursor); |
2691 |
|
|
2692 |
SET_SCROLL_BAR_X_WINDOW (bar, scroll_id); |
SET_SCROLL_BAR_X_WINDOW (bar, scroll_id); |
2693 |
} |
} |
3106 |
event->area.x -= width > event->area.width ? width-event->area.width : 0; |
event->area.x -= width > event->area.width ? width-event->area.width : 0; |
3107 |
event->area.y -= height > event->area.height ? height-event->area.height : 0; |
event->area.y -= height > event->area.height ? height-event->area.height : 0; |
3108 |
|
|
3109 |
event->area.x = max(0, event->area.x); |
event->area.x = max (0, event->area.x); |
3110 |
event->area.y = max(0, event->area.y); |
event->area.y = max (0, event->area.y); |
3111 |
|
|
3112 |
event->area.width = max (width, event->area.width); |
event->area.width = max (width, event->area.width); |
3113 |
event->area.height = max (height, event->area.height); |
event->area.height = max (height, event->area.height); |
3129 |
GdkEventExpose *event; |
GdkEventExpose *event; |
3130 |
gpointer client_data; |
gpointer client_data; |
3131 |
{ |
{ |
3132 |
update_frame_tool_bar((FRAME_PTR)client_data); |
update_frame_tool_bar ((FRAME_PTR) client_data); |
3133 |
return FALSE; |
return FALSE; |
3134 |
} |
} |
3135 |
|
|
3262 |
|
|
3263 |
if (! wicon) |
if (! wicon) |
3264 |
{ |
{ |
3265 |
GdkPixmap *gpix = gdk_pixmap_foreign_new (img->pixmap); |
GdkPixmap *gpix; |
3266 |
GdkBitmap *gmask = img->mask ? |
GdkBitmap *gmask; |
3267 |
(GdkBitmap*) gdk_pixmap_foreign_new (img->mask) : 0; |
GtkWidget *w; |
3268 |
|
|
3269 |
GtkWidget *w = gtk_image_new_from_pixmap (gpix, gmask); |
xg_get_gdk_pixmap_and_mask (f, img, &gpix, &gmask); |
3270 |
|
w = gtk_image_new_from_pixmap (gpix, gmask); |
3271 |
gtk_toolbar_append_item (GTK_TOOLBAR (x->toolbar_widget), |
gtk_toolbar_append_item (GTK_TOOLBAR (x->toolbar_widget), |
3272 |
0, 0, 0, |
0, 0, 0, |
3273 |
w, |
w, |
3325 |
|
|
3326 |
if (old_img != img->pixmap) |
if (old_img != img->pixmap) |
3327 |
{ |
{ |
3328 |
GdkPixmap *gpix = gdk_pixmap_foreign_new (img->pixmap); |
GdkPixmap *gpix; |
3329 |
GdkBitmap *gmask = img->mask ? |
GdkBitmap *gmask; |
|
(GdkBitmap*) gdk_pixmap_foreign_new (img->mask) : 0; |
|
3330 |
|
|
3331 |
|
xg_get_gdk_pixmap_and_mask (f, img, &gpix, &gmask); |
3332 |
gtk_image_set_from_pixmap (wimage, gpix, gmask); |
gtk_image_set_from_pixmap (wimage, gpix, gmask); |
3333 |
} |
} |
3334 |
|
|
3396 |
xg_initialize () |
xg_initialize () |
3397 |
{ |
{ |
3398 |
xg_ignore_gtk_scrollbar = 0; |
xg_ignore_gtk_scrollbar = 0; |
|
xg_left_ptr_cursor = 0; |
|
3399 |
xg_detached_menus = 0; |
xg_detached_menus = 0; |
3400 |
xg_menu_cb_list.prev = xg_menu_cb_list.next = |
xg_menu_cb_list.prev = xg_menu_cb_list.next = |
3401 |
xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0; |
xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0; |