2 /******************************************************************************
3 * MODULE : x_window.cpp
4 * DESCRIPTION: Windows under X11
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license and comes WITHOUT
8 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
9 * If you don't have this file, write to the Free Software Foundation, Inc.,
10 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11 ******************************************************************************/
13 #include "X11/x_window.hpp"
14 #include "message.hpp"
16 extern int nr_windows
;
18 hashmap
<Window
,pointer
> Window_to_window (NULL
);
20 /******************************************************************************
21 * Creation and deletion of an x_window
22 ******************************************************************************/
25 x_window_rep::set_hints (SI min_w
, SI min_h
, SI max_w
, SI max_h
) {
26 XSizeHints
* size_hints
;
28 XClassHint
* class_hints
;
29 if (!(size_hints
= XAllocSizeHints ()))
30 fatal_error ("out of memory (X server)", "set_attributes");
31 if (!(wm_hints
= XAllocWMHints ()))
32 fatal_error ("out of memory (X server)", "set_attributes");
33 if (!(class_hints
= XAllocClassHint ()))
34 fatal_error ("out of memory (X server)", "set_attributes");
36 XTextProperty Window_Name
;
37 XTextProperty Icon_Name
;
38 if (XStringListToTextProperty (&name
, 1, &Window_Name
) == 0)
39 fatal_error ("out of memory (X server)", "set_attributes");
40 if (XStringListToTextProperty (&name
, 1, &Icon_Name
) == 0)
41 fatal_error ("out of memory (X server)", "set_attributes");
43 // int start_1= texmacs_time ();
44 if (!gui
->xpm_pixmap
->contains ("TeXmacs.xpm"))
45 xpm_initialize ("TeXmacs.xpm");
46 Pixmap pm
= (Pixmap
) gui
->xpm_pixmap
["TeXmacs.xpm"];
47 // cout << "Getting pixmap required " << (texmacs_time ()-start_1) << " ms\n";
49 // int start_2= texmacs_time ();
50 size_hints
->flags
= PPosition
| PSize
| PMinSize
| PMaxSize
;
51 size_hints
->min_width
= min_w
;
52 size_hints
->min_height
= min_h
;
53 size_hints
->max_width
= max_w
;
54 size_hints
->max_height
= max_h
;
55 wm_hints
->initial_state
= NormalState
;
56 wm_hints
->input
= true;
57 wm_hints
->icon_pixmap
= pm
;
58 wm_hints
->flags
= StateHint
| IconPixmapHint
| InputHint
;
59 class_hints
->res_name
= name
;
60 class_hints
->res_class
= name
;
73 // cout << "Setting hints required " << (texmacs_time ()-start_2) << " ms\n";
77 x_window_rep::initialize () {
78 SI min_w
= Min_w
, min_h
= Min_h
;
79 SI def_w
= Def_w
, def_h
= Def_h
;
80 SI max_w
= Max_w
, max_h
= Max_h
;
84 full_screen_flag
= false;
86 // int start_1= texmacs_time ();
88 decode (def_w
, def_h
); def_h
= -def_h
;
89 decode (min_w
, min_h
); min_h
= -min_h
;
90 decode (max_w
, max_h
); max_h
= -max_h
;
91 // cout << "Size computation required " << (texmacs_time ()-start_1) << " ms\n";
93 // int start_2= texmacs_time ();
94 unsigned long valuemask
= CWOverrideRedirect
| CWSaveUnder
;
95 //unsigned long valuemask= CWOverrideRedirect | CWSaveUnder | CWBackingStore;
96 XSetWindowAttributes setattr
;
97 setattr
.override_redirect
= (name
==NULL
);
98 setattr
.save_under
= True
; // (name==NULL);
99 // setattr.backing_store = Always;
100 // FIXME: backing store does not seem to work correctly
101 if (win_w
== 0) win_w
= def_w
;
102 if (win_h
== 0) win_h
= def_h
;
103 if ((win_x
+ win_w
) > gui
->screen_width
) win_x
= gui
->screen_width
- win_w
;
104 if (win_x
< 0) win_x
= 0;
105 if ((win_y
+ win_h
) > gui
->screen_height
) win_y
= gui
->screen_height
- win_h
;
106 if (win_y
< 0) win_y
=0;
107 win
= XCreateWindow (dpy
, gui
->root
, win_x
, win_y
, win_w
, win_h
, 0,
108 gui
->depth
, InputOutput
, CopyFromParent
,
109 valuemask
, &setattr
);
110 x_drawable_rep::win
= (Drawable
) win
;
111 // cout << "XWindow creation required " << (texmacs_time ()-start_2) << " ms\n";
113 // cout << "Hints: " << min_w << ", " << min_h << " --- "
114 // << max_w << ", " << max_h << "\n";
115 if (name
== NULL
) name
= const_cast<char*> ("popup");
116 if (the_name
== "") the_name
= name
;
117 set_hints (min_w
, min_h
, max_w
, max_h
);
119 unsigned long ic_mask
= 0;
122 ic
= XCreateIC (gui
->im
,
123 XNInputStyle
, XIMPreeditNothing
| XIMStatusNothing
,
127 cout
<< "TeXmacs] Warning: couldn't create input context\n";
130 XGetICValues (ic
, XNFilterEvents
, &ic_mask
, NULL
);
134 XSelectInput (dpy
, win
,
135 ExposureMask
| StructureNotifyMask
|
136 SubstructureNotifyMask
| FocusChangeMask
|
137 PointerMotionMask
| EnterWindowMask
| LeaveWindowMask
|
138 ButtonPressMask
| ButtonReleaseMask
|
139 KeyPressMask
| ic_mask
);
141 Atom wm_protocols
= XInternAtom(dpy
, "WM_PROTOCOLS", 1);
142 Atom wm_delete_window
= XInternAtom(dpy
, "WM_DELETE_WINDOW", 1);
143 XSetWMProtocols (dpy
, win
, &wm_protocols
, 1);
144 XSetWMProtocols (dpy
, win
, &wm_delete_window
, 1);
147 Window_to_window (win
)= (void*) this;
148 set_identifier (w
, (int) win
);
149 notify_position (w
, 0, 0);
150 notify_size (w
, Def_w
, Def_h
);
153 x_window_rep::x_window_rep (widget w2
, x_gui gui2
, char* n2
,
154 SI min_w
, SI min_h
, SI def_w
, SI def_h
,
156 x_drawable_rep (gui2
), window_rep (), w (w2
), gui (gui2
), name (n2
),
157 Min_w (min_w
), Min_h (min_h
), Def_w (def_w
), Def_h (def_h
),
158 Max_w (max_w
), Max_h (max_h
),
159 win_x (0), win_y (0), win_w (Def_w
/PIXEL
), win_h (Def_h
/PIXEL
),
160 kbd_focus (w
.rep
), has_focus (false)
163 gui
->created_window (win
);
166 x_window_rep::~x_window_rep () {
167 set_identifier (w
, 0);
170 while (XCheckWindowEvent (dpy
, win
, 0xffffffff, &report
));
172 if (ic_ok
) XDestroyIC (ic
);
173 Window_to_window
->reset (win
);
175 XDestroyWindow (dpy
, win
);
176 gui
->deleted_window (win
);
180 x_window_rep::get_widget () {
185 x_window_rep::get_extents (int& w
, int& h
) {
191 get_Window (widget w
) {
192 int id
= get_identifier (w
);
194 cerr
<< "\nwidget = " << w
<< "\n";
195 fatal_error ("widget is not attached to a window", "get_Window");
201 get_x_window (widget w
) {
202 int id
= get_identifier (w
);
203 if (id
== 0) return NULL
;
204 else return (x_window
) Window_to_window
[(Window
) id
];
208 get_identifier (window w
) {
209 if (w
== NULL
) return 0;
210 else return (int) (((x_window
) w
) -> win
);
214 get_window (int id
) {
215 if (id
== 0) return NULL
;
216 else return (window
) ((x_window
) Window_to_window
[(Window
) id
]);
219 /******************************************************************************
220 * Window apping and appearance
221 ******************************************************************************/
224 x_window_rep::get_position (SI
& x
, SI
& y
) {
226 XGetWindowPos (dpy
, win
, &win_x
, &win_y
);
233 b
= XTranslateCoordinates (dpy
, win
, gui
->root
, 0, 0, &xx
, &yy
, &ww
);
240 x_window_rep::get_size (SI
& ww
, SI
& hh
) {
246 x_window_rep::set_position (SI x
, SI y
) {
249 if ((x
+ win_w
) > gui
->screen_width
) x
= gui
->screen_width
- win_w
;
251 if ((y
+ win_h
) > gui
->screen_height
) y
= gui
->screen_height
- win_h
;
253 XMoveWindow (dpy
, win
, x
, y
);
257 x_window_rep::set_size (SI w
, SI h
) {
259 XResizeWindow (dpy
, win
, w
, h
);
263 x_window_rep::set_name (string name
) {
264 char* s
= as_charp (name
);
265 XStoreName (dpy
, win
, s
);
266 XSetIconName (dpy
, win
, s
);
272 x_window_rep::get_name () {
277 x_window_rep::set_visibility (bool flag
) {
278 if (flag
) XMapRaised (dpy
, win
);
279 else XUnmapWindow (dpy
, win
);
283 x_window_rep::set_full_screen (bool flag
) {
284 if (full_screen_flag
== flag
) return;
285 string old_name
= get_name ();
287 old_name
= as_string (name
);
291 save_x
= win_x
; save_y
= win_y
;
292 save_w
= win_w
; save_h
= win_h
;
294 XMoveResizeWindow (dpy
, win
, 0, 0,
295 gui
->screen_width
, gui
->screen_height
);
297 resize_event (gui
->screen_width
, gui
->screen_height
);
298 set_visibility (true);
299 XSetInputFocus (dpy
, win
, PointerRoot
, CurrentTime
);
302 set_visibility (false);
303 Window_to_window
->reset (win
);
305 XDestroyWindow (dpy
, win
);
307 set_visibility (false);
308 Window_to_window
->reset (win
);
310 XDestroyWindow (dpy
, win
);
311 name
= as_charp (old_name
);
312 win_x
= save_x
; win_y
= save_y
;
313 win_w
= save_w
; win_h
= save_h
;
315 set_visibility (true);
316 XMoveResizeWindow (dpy
, win
, save_x
, save_y
, save_w
, save_h
);
317 resize_event (save_w
, save_h
);
318 move_event (save_x
, save_y
);
321 full_screen_flag
= flag
;
325 x_window_rep::move_event (int x
, int y
) {
326 bool flag
= (win_x
!=x
) || (win_y
!=y
);
328 if (flag
) notify_position (w
, win_x
*PIXEL
, win_y
*PIXEL
);
332 x_window_rep::resize_event (int ww
, int hh
) {
333 bool flag
= (win_w
!=ww
) || (win_h
!=hh
);
334 win_w
= ww
; win_h
= hh
;
335 if (flag
) notify_size (w
, win_w
*PIXEL
, win_h
*PIXEL
);
339 x_window_rep::destroy_event () {
343 /******************************************************************************
345 ******************************************************************************/
348 x_window_rep::invalidate_event (int x1
, int y1
, int x2
, int y2
) {
349 invalid_regions
= invalid_regions
| rectangles (rectangle (x1
, y1
, x2
, y2
));
353 x_window_rep::key_event (string key
) {
354 send_keyboard (kbd_focus
, key
);
358 x_window_rep::focus_in_event () {
359 if (ic_ok
) XSetICFocus (ic
);
361 notify_keyboard_focus (kbd_focus
, true);
362 gui
->focussed_window (win
);
366 x_window_rep::focus_out_event () {
367 if (ic_ok
) XUnsetICFocus (ic
);
369 notify_keyboard_focus (kbd_focus
, false);
373 x_window_rep::mouse_event (string ev
, int x
, int y
, time_t t
) {
374 if (nil (gui
->grab_ptr
) || (get_x_window (gui
->grab_ptr
->item
) == NULL
)) {
377 send_mouse (w
, ev
, x
, y
, gui
->state
, t
);
380 x_window grab_win
= get_x_window (gui
->grab_ptr
->item
);
381 if (this != grab_win
) {
382 x
+= win_x
- grab_win
->win_x
;
383 y
+= win_y
- grab_win
->win_y
;
388 send_mouse (gui
->grab_ptr
->item
, ev
, x
, y
, gui
->state
, t
);
393 x_window_rep::repaint_invalid_regions () {
394 //if (!nil (invalid_regions)) cout << invalid_regions << "\n";
395 //else { cout << "."; cout.flush (); }
396 rectangles new_regions
;
397 if (!nil (invalid_regions
)) {
398 rectangle lub
= least_upper_bound (invalid_regions
);
399 if (area (lub
) < 1.2 * area (invalid_regions
))
400 invalid_regions
= rectangles (lub
);
402 while (!nil (invalid_regions
)) {
404 rectangle r
= copy (invalid_regions
->item
);
405 encode (r
->x1
, r
->y1
);
406 encode (r
->x2
, r
->y2
);
407 x_drawable_rep::set_clipping (r
->x1
, r
->y2
, r
->x2
, r
->y1
);
408 send_repaint (w
, r
->x1
, r
->y2
, r
->x2
, r
->y1
);
410 new_regions
= rectangles (invalid_regions
->item
, new_regions
);
411 invalid_regions
= invalid_regions
->next
;
413 invalid_regions
= new_regions
;
417 x_window_rep::set_keyboard_focus (widget wid
, bool get_focus
) {
419 fatal_error ("Explicit loss of keyboard focus not yet implemented",
420 "x_window_rep::set_keyboard_focus");
421 if (has_focus
&& (kbd_focus
!= wid
.rep
)) {
422 notify_keyboard_focus (kbd_focus
, false);
423 notify_keyboard_focus (wid
, true);
429 x_window_rep::get_keyboard_focus (widget wid
) {
430 return has_focus
&& kbd_focus
== wid
.rep
;
434 x_window_rep::set_mouse_grab (widget wid
, bool get_grab
) {
435 if (get_grab
) gui
->obtain_mouse_grab (wid
);
436 else gui
->release_mouse_grab ();
440 x_window_rep::get_mouse_grab (widget w
) {
441 return gui
->has_mouse_grab (w
);
445 x_window_rep::set_mouse_pointer (widget wid
, string name
, string mask
) {
446 if (mask
== "") gui
->set_mouse_pointer (wid
, name
);
447 else gui
->set_mouse_pointer (wid
, name
, mask
);
450 /******************************************************************************
452 ******************************************************************************/
454 message_rep::message_rep (widget wid2
, string s2
, time_t t2
):
455 wid (wid2
), s (s2
), t (t2
) {}
456 message::message (widget wid
, string s
, time_t t
):
457 rep (new message_rep (wid
, s
, t
)) {}
460 operator << (ostream
& out
, message m
) {
461 return out
<< "message " << m
->s
<< " to " << m
->wid
462 << "at time " << m
->t
<< "\n";
466 insert_message (list
<message
> l
, widget wid
, string s
, time_t cur
, time_t t
) {
467 if (nil (l
)) return list
<message
> (message (wid
, s
, t
));
468 time_t ref
= l
->item
->t
;
469 if ((t
-cur
) <= (ref
-cur
)) return list
<message
> (message (wid
, s
, t
), l
);
470 return list
<message
> (l
->item
, insert_message (l
->next
, wid
, s
, cur
, t
));
474 x_window_rep::delayed_message (widget wid
, string s
, time_t delay
) {
475 time_t ct
= texmacs_time ();
476 the_gui
->messages
= insert_message (the_gui
->messages
, wid
, s
, ct
, ct
+ delay
);
479 /******************************************************************************
480 * Routines concerning regions in a window
481 ******************************************************************************/
484 x_window_rep::translate (SI x1
, SI y1
, SI x2
, SI y2
, SI dx
, SI dy
) {
494 while (XCheckWindowEvent (dpy
, win
, ExposureMask
, &report
))
495 gui
->process_event (this, &report
);
497 rectangles
region (rectangle (x1
, y2
, x2
, y1
));
498 rectangles invalid_intern
= invalid_regions
& region
;
499 rectangles invalid_extern
= invalid_regions
- invalid_intern
;
500 invalid_intern
= ::translate (invalid_intern
, dx
, dy
) & region
;
501 invalid_regions
= invalid_extern
| invalid_intern
;
504 XCopyArea (dpy
, win
, win
, gc
, x1
, y2
, x2
-x1
, y1
-y2
, X1
, Y2
);
508 x_window_rep::invalidate (SI x1
, SI y1
, SI x2
, SI y2
) {
509 outer_round (x1
, y1
, x2
, y2
);
512 invalidate_event (x1
, y2
, x2
, y1
);
516 x_window_rep::repainted () {
517 return nil (invalid_regions
);
520 /******************************************************************************
522 ******************************************************************************/
525 popup_window (widget w
, string name
, SI min_w
, SI min_h
,
526 SI def_w
, SI def_h
, SI max_w
, SI max_h
)
528 char* _name
= as_charp (name
);
529 window win
= new x_window_rep (w
, the_gui
, NULL
,
530 min_w
, min_h
, def_w
, def_h
, max_w
, max_h
);
536 plain_window (widget w
, string name
, SI min_w
, SI min_h
,
537 SI def_w
, SI def_h
, SI max_w
, SI max_h
)
539 char* _name
= as_charp (name
);
540 window win
= new x_window_rep (w
, the_gui
, _name
,
541 min_w
, min_h
, def_w
, def_h
, max_w
, max_h
);