Back to index

texmacs  1.0.7.15
x_window.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : x_window.cpp
00004 * DESCRIPTION: Windows under X11
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "X11/x_window.hpp"
00013 #include "message.hpp"
00014 
00015 extern int nr_windows;
00016 
00017 hashmap<Window,pointer> Window_to_window (NULL);
00018 
00019 /******************************************************************************
00020 * Creation and deletion of an x_window
00021 ******************************************************************************/
00022 
00023 void
00024 x_window_rep::set_hints (SI min_w, SI min_h, SI max_w, SI max_h) {
00025   XSizeHints* size_hints;
00026   XWMHints*   wm_hints;
00027   XClassHint* class_hints;
00028   ASSERT (size_hints= XAllocSizeHints (), "out of memory (X server)");
00029   ASSERT (wm_hints= XAllocWMHints (), "out of memory (X server)");
00030   ASSERT (class_hints= XAllocClassHint (), "out of memory (X server)");
00031 
00032   XTextProperty Window_Name;
00033   XTextProperty Icon_Name;
00034   ASSERT (XStringListToTextProperty (&name, 1, &Window_Name) != 0,
00035          "out of memory (X server)");
00036   ASSERT (XStringListToTextProperty (&name, 1, &Icon_Name) != 0,
00037          "out of memory (X server)");
00038 
00039   // time_t start_1= texmacs_time ();
00040   if (!gui->xpm_pixmap->contains ("TeXmacs.xpm"))
00041     ren->xpm_initialize ("TeXmacs.xpm");
00042   Pixmap pm= (Pixmap) gui->xpm_pixmap ["TeXmacs.xpm"];
00043   // cout << "Getting pixmap required " << (texmacs_time ()-start_1) << " ms\n";
00044 
00045   // time_t start_2= texmacs_time ();
00046   size_hints->flags       = PPosition | PSize | PMinSize | PMaxSize;
00047   size_hints->min_width   = min_w;
00048   size_hints->min_height  = min_h;
00049   size_hints->max_width   = max_w;
00050   size_hints->max_height  = max_h;
00051   wm_hints->initial_state = NormalState;
00052   wm_hints->input         = true;
00053   wm_hints->icon_pixmap   = pm;
00054   wm_hints->flags         = StateHint | IconPixmapHint | InputHint;
00055   class_hints->res_name   = name;
00056   class_hints->res_class  = name;
00057 
00058   XSetWMProperties (
00059     dpy,
00060     win,
00061     &Window_Name,
00062     &Icon_Name,
00063     gui->argv,
00064     gui->argc,
00065     size_hints,
00066     wm_hints,
00067     class_hints
00068   );
00069 
00070   XFree(size_hints);
00071   XFree(wm_hints);
00072   XFree(class_hints);
00073   XFree(Window_Name.value);
00074   XFree(Icon_Name.value);
00075   // cout << "Setting hints required " << (texmacs_time ()-start_2) << " ms\n";
00076 }
00077 
00078 void
00079 x_window_rep::initialize () {
00080   SI min_w= Min_w, min_h= Min_h;
00081   SI def_w= Def_w, def_h= Def_h;
00082   SI max_w= Max_w, max_h= Max_h;
00083 
00084   dpy= gui->dpy;
00085   gc = gui->gc;
00086   full_screen_flag= false;
00087 
00088   // time_t start_1= texmacs_time ();
00089   ren->set_origin (0, 0);
00090   ren->decode (def_w, def_h); def_h= -def_h;
00091   ren->decode (min_w, min_h); min_h= -min_h;
00092   ren->decode (max_w, max_h); max_h= -max_h;
00093   // cout << "Size computation required " << (texmacs_time ()-start_1) << " ms\n";
00094 
00095   // time_t start_2= texmacs_time ();
00096   unsigned long valuemask= CWOverrideRedirect | CWSaveUnder;
00097   //unsigned long valuemask= CWOverrideRedirect | CWSaveUnder | CWBackingStore;
00098   XSetWindowAttributes setattr;
00099   setattr.override_redirect= (name==NULL);
00100   setattr.save_under       = True; // (name==NULL);
00101   // setattr.backing_store    = Always;
00102   // FIXME: backing store does not seem to work correctly
00103   if (win_w == 0) win_w= def_w;
00104   if (win_h == 0) win_h= def_h;
00105   if ((win_x+ win_w) > gui->screen_width) win_x= gui->screen_width- win_w;
00106   if (win_x < 0) win_x= 0;
00107   if ((win_y+ win_h) > gui->screen_height) win_y= gui->screen_height- win_h;
00108   if (win_y < 0) win_y=0;
00109   win= XCreateWindow (dpy, gui->root, win_x, win_y, win_w, win_h, 0,
00110                     gui->depth, InputOutput, CopyFromParent,
00111                     valuemask, &setattr);
00112   ren->win= (Drawable) win;
00113   // cout << "XWindow creation required " << (texmacs_time ()-start_2) << " ms\n";
00114 
00115   //cout << "Hints: "
00116   //     << min_w << ", " << min_h << " --- "
00117   //     << def_w << ", " << def_h << " --- "
00118   //     << max_w << ", " << max_h << "\n";
00119   if (name == NULL) name= const_cast<char*> ("popup");
00120   if (the_name == "") the_name= name;
00121   set_hints (min_w, min_h, max_w, max_h);
00122 
00123   unsigned long ic_mask= 0;
00124   ic_ok= false;
00125   if (gui->im_ok) {
00126     ic= XCreateIC (gui->im,
00127                  XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
00128                  XNClientWindow, win,
00129                  NULL);
00130     if (ic == NULL)
00131       cout << "TeXmacs] Warning: couldn't create input context\n";
00132     else {
00133       ic_ok= true;
00134       XGetICValues (ic, XNFilterEvents, &ic_mask, NULL);
00135     }
00136   }
00137 
00138   XSelectInput (dpy, win,
00139               ExposureMask | StructureNotifyMask |
00140               SubstructureNotifyMask | FocusChangeMask |
00141               PointerMotionMask | EnterWindowMask | LeaveWindowMask |
00142               ButtonPressMask | ButtonReleaseMask |
00143               KeyPressMask | ic_mask);
00144 
00145   Atom wm_protocols     = XInternAtom(dpy, "WM_PROTOCOLS", 1);
00146   Atom wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", 1);
00147   XSetWMProtocols (dpy, win, &wm_protocols, 1);
00148   XSetWMProtocols (dpy, win, &wm_delete_window, 1);
00149 
00150   nr_windows++;
00151   Window_to_window (win)= (void*) this;
00152   set_identifier (w, (int) win);
00153   notify_position (w, 0, 0);
00154   notify_size (w, Def_w, Def_h);
00155 }
00156 
00157 x_window_rep::x_window_rep (widget w2, x_gui gui2, char* n2,
00158                          SI min_w, SI min_h, SI def_w, SI def_h,
00159                          SI max_w, SI max_h):
00160   window_rep (), w (w2), gui (gui2), name (n2),
00161   ren (tm_new<x_drawable_rep> (gui2, this)),
00162   Min_w (min_w), Min_h (min_h), Def_w (def_w), Def_h (def_h),
00163   Max_w (max_w), Max_h (max_h),
00164   win_x (0), win_y (0), win_w (Def_w/PIXEL), win_h (Def_h/PIXEL),
00165   kbd_focus (w.rep), has_focus (false)
00166 {
00167   //cout << "Min " << (min_w >> 8) << ", " << (min_h >> 8) << "\n";
00168   //cout << "Def " << (def_w >> 8) << ", " << (def_h >> 8) << "\n";
00169   //cout << "Max " << (max_w >> 8) << ", " << (max_h >> 8) << "\n";
00170   initialize ();
00171   gui->created_window (win);
00172 }
00173 
00174 x_window_rep::~x_window_rep () {
00175   set_identifier (w, 0);
00176 
00177   XEvent report;
00178   while (XCheckWindowEvent (dpy, win, 0xffffffff, &report));
00179 
00180   tm_delete (ren);
00181   if (ic_ok) XDestroyIC (ic);
00182   Window_to_window->reset (win);
00183   nr_windows--;
00184   XDestroyWindow (dpy, win);
00185   gui->deleted_window (win);
00186 }
00187 
00188 widget
00189 x_window_rep::get_widget () {
00190   return w;
00191 }
00192 
00193 renderer
00194 x_window_rep::get_renderer () {
00195   return (renderer) ren;
00196 }
00197 
00198 void
00199 x_window_rep::get_extents (int& w, int& h) {
00200   w= win_w;
00201   h= win_h;
00202 }
00203 
00204 Window
00205 get_Window (widget w) {
00206   int id= get_identifier (w);
00207   if (id == 0) {
00208     cerr << "\nwidget = " << w << "\n";
00209     FAILED ("widget is not attached to a window");
00210   }
00211   return (Window) id;
00212 }
00213 
00214 x_window
00215 get_x_window (widget w) {
00216   int id= get_identifier (w);
00217   if (id == 0) return NULL;
00218   else return (x_window) Window_to_window[(Window) id];
00219 }
00220 
00221 int
00222 get_identifier (window w) {
00223   if (w == NULL) return 0;
00224   else return (int) (((x_window) w) -> win);
00225 }
00226 
00227 window
00228 get_window (int id) {
00229   if (id == 0) return NULL;
00230   else return (window) ((x_window) Window_to_window[(Window) id]);
00231 }
00232 
00233 /******************************************************************************
00234 * Window apping and appearance
00235 ******************************************************************************/
00236 
00237 void
00238 x_window_rep::get_position (SI& x, SI& y) {
00239 #ifdef OS_WIN32
00240   XGetWindowPos (dpy, win, &win_x, &win_y);
00241   x=  win_x*PIXEL;
00242   y= -win_y*PIXEL;
00243 #else
00244   int xx, yy;
00245   Window ww;
00246   bool b;
00247   b=  XTranslateCoordinates (dpy, win, gui->root, 0, 0, &xx, &yy, &ww);
00248   x=  xx*PIXEL;
00249   y= -yy*PIXEL;
00250 #endif
00251 }
00252 
00253 void
00254 x_window_rep::get_size (SI& ww, SI& hh) {
00255   ww= win_w*PIXEL;
00256   hh= win_h*PIXEL;
00257 }
00258 
00259 void
00260 x_window_rep::get_size_limits (SI& min_w, SI& min_h, SI& max_w, SI& max_h) {
00261   min_w= Min_w; min_h= Min_h; max_w= Max_w; max_h= Max_h;
00262 }
00263 
00264 void
00265 x_window_rep::set_position (SI x, SI y) {
00266   x= x/PIXEL;
00267   y= -y/PIXEL;
00268   if ((x+ win_w) > gui->screen_width) x= gui->screen_width- win_w;
00269   if (x<0) x=0;
00270   if ((y+ win_h) > gui->screen_height) y= gui->screen_height- win_h;
00271   if (y<0) y=0;
00272   XMoveWindow (dpy, win, x, y);
00273 }
00274 
00275 void
00276 x_window_rep::set_size (SI w, SI h) {
00277   w= w/PIXEL; h= h/PIXEL;
00278   //h=-h; ren->decode (w, h);
00279   XResizeWindow (dpy, win, w, h);
00280 }
00281 
00282 void
00283 x_window_rep::set_size_limits (SI min_w, SI min_h, SI max_w, SI max_h) {
00284   if (min_w == Min_w && min_h == Min_h && max_w == Max_w && max_h == Max_h)
00285     return;
00286   Min_w= min_w; Min_h= min_h; Max_w= max_w; Max_h= max_h;
00287   min_w= min_w/PIXEL; min_h= min_h/PIXEL;
00288   max_w= max_w/PIXEL; max_h= max_h/PIXEL;
00289 
00290   XSizeHints* size_hints;
00291   ASSERT (size_hints= XAllocSizeHints (), "out of memory (X server)");
00292   size_hints->flags       = PMinSize | PMaxSize;
00293   size_hints->min_width   = min_w;
00294   size_hints->min_height  = min_h;
00295   size_hints->max_width   = max_w;
00296   size_hints->max_height  = max_h;
00297   XSetWMNormalHints (dpy, win, size_hints);
00298   XFree(size_hints);
00299 }
00300 
00301 void
00302 x_window_rep::set_name (string name) {
00303   char* s= as_charp (name);
00304   XStoreName (dpy, win, s);
00305   XSetIconName (dpy, win, s);
00306   tm_delete_array (s);
00307   the_name= name;
00308 }
00309 
00310 string
00311 x_window_rep::get_name () {
00312   return the_name;
00313 }
00314 
00315 void
00316 x_window_rep::set_visibility (bool flag) {
00317   if (flag) XMapRaised (dpy, win);
00318   else XUnmapWindow (dpy, win);
00319 }
00320 
00321 void
00322 x_window_rep::set_full_screen (bool flag) {
00323   if (full_screen_flag == flag) return;
00324   string old_name= get_name ();
00325   if (old_name == "")
00326     old_name= as_string (name);
00327   if (flag) {
00328     save_win= win;
00329     name= NULL;
00330     save_x= win_x; save_y= win_y;
00331     save_w= win_w; save_h= win_h;
00332     initialize ();
00333     XMoveResizeWindow (dpy, win, 0, 0,
00334                      gui->screen_width, gui->screen_height);
00335     move_event   (0, 0);
00336     resize_event (gui->screen_width, gui->screen_height);
00337     set_visibility (true);
00338     XSetInputFocus (dpy, win, PointerRoot, CurrentTime);
00339   }
00340   else {
00341     set_visibility (false);
00342     Window_to_window->reset (win);
00343     nr_windows--;
00344     XDestroyWindow (dpy, win);
00345     win= save_win;
00346     set_visibility (false);
00347     Window_to_window->reset (win);
00348     nr_windows--;
00349     XDestroyWindow (dpy, win);
00350     name= as_charp (old_name);
00351     win_x= save_x; win_y= save_y;
00352     win_w= save_w; win_h= save_h;
00353     initialize ();
00354     set_visibility (true);
00355     XMoveResizeWindow (dpy, win, save_x, save_y, save_w, save_h);
00356     resize_event (save_w, save_h);
00357     move_event   (save_x, save_y);
00358   }
00359   set_name (old_name);
00360   full_screen_flag= flag;
00361 }
00362 
00363 void
00364 x_window_rep::move_event (int x, int y) {
00365   bool flag= (win_x!=x) || (win_y!=y);
00366   win_x= x; win_y= y;
00367   if (flag) notify_position (w, win_x*PIXEL, win_y*PIXEL);
00368 }
00369 
00370 void
00371 x_window_rep::resize_event (int ww, int hh) {
00372   bool flag= (win_w!=ww) || (win_h!=hh);
00373   win_w= ww; win_h= hh;
00374   if (flag) notify_size (w, win_w*PIXEL, win_h*PIXEL);
00375 }
00376 
00377 void
00378 x_window_rep::destroy_event () {
00379   send_destroy (w);
00380 }
00381 
00382 /******************************************************************************
00383 * Event handling
00384 ******************************************************************************/
00385 
00386 void
00387 x_window_rep::invalidate_event (int x1, int y1, int x2, int y2) {
00388   invalid_regions= invalid_regions | rectangles (rectangle (x1, y1, x2, y2));
00389 }
00390 
00391 void
00392 x_window_rep::key_event (string key) {
00393   send_keyboard (kbd_focus, key);
00394 }
00395 
00396 void
00397 x_window_rep::focus_in_event () {
00398   if (ic_ok) XSetICFocus (ic);
00399   has_focus= true;
00400   notify_keyboard_focus (kbd_focus, true);
00401   gui->focussed_window (win);
00402 }
00403 
00404 void
00405 x_window_rep::focus_out_event () {
00406   if (ic_ok) XUnsetICFocus (ic);
00407   has_focus= false;
00408   notify_keyboard_focus (kbd_focus, false);
00409 }
00410 
00411 void
00412 x_window_rep::mouse_event (string ev, int x, int y, time_t t) {
00413   if (is_nil (gui->grab_ptr) || (get_x_window (gui->grab_ptr->item) == NULL)) {
00414     ren->set_origin (0, 0);
00415     ren->encode (x, y);
00416     send_mouse (w, ev, x, y, gui->state, t);
00417   }
00418   else {
00419     x_window grab_win= get_x_window (gui->grab_ptr->item);
00420     if (this != grab_win) {
00421       x += win_x - grab_win->win_x;
00422       y += win_y - grab_win->win_y;
00423       // return;
00424     }
00425     ren->set_origin (0, 0);
00426     ren->encode (x, y);
00427     send_mouse (gui->grab_ptr->item, ev, x, y, gui->state, t);
00428   }
00429 }
00430 
00431 void
00432 x_window_rep::repaint_invalid_regions () {
00433   //if (!is_nil (invalid_regions)) cout << invalid_regions << "\n";
00434   //else { cout << "."; cout.flush (); }
00435   rectangles new_regions;
00436   if (!is_nil (invalid_regions)) {
00437     rectangle lub= least_upper_bound (invalid_regions);
00438     if (area (lub) < 1.2 * area (invalid_regions))
00439       invalid_regions= rectangles (lub);
00440   }
00441   while (!is_nil (invalid_regions)) {
00442     ren->set_origin (0, 0);
00443     rectangle r= copy (invalid_regions->item);
00444     ren->encode (r->x1, r->y1);
00445     ren->encode (r->x2, r->y2);
00446     ren->set_clipping (r->x1, r->y2, r->x2, r->y1);
00447     send_repaint (w, r->x1, r->y2, r->x2, r->y1);
00448     if (ren->interrupted ())
00449       new_regions= rectangles (invalid_regions->item, new_regions);
00450     invalid_regions= invalid_regions->next;
00451   }
00452   invalid_regions= new_regions;
00453 }
00454 
00455 void
00456 x_window_rep::set_keyboard_focus (widget wid, bool get_focus) {
00457   ASSERT (get_focus, "explicit loss of keyboard focus not yet implemented");
00458   if (has_focus && (kbd_focus != wid.rep)) {
00459     notify_keyboard_focus (kbd_focus, false);
00460     notify_keyboard_focus (wid, true);
00461   }
00462   kbd_focus= wid.rep;
00463 }
00464 
00465 bool
00466 x_window_rep::get_keyboard_focus (widget wid) {
00467   return has_focus && kbd_focus == wid.rep;
00468 }
00469 
00470 void
00471 x_window_rep::set_mouse_grab (widget wid, bool get_grab) {
00472   if (get_grab) gui->obtain_mouse_grab (wid);
00473   else gui->release_mouse_grab ();
00474 }
00475 
00476 bool
00477 x_window_rep::get_mouse_grab (widget w) {
00478   return gui->has_mouse_grab (w);
00479 }
00480 
00481 void
00482 x_window_rep::set_mouse_pointer (widget wid, string name, string mask) {
00483   if (mask == "") gui->set_mouse_pointer (wid, name);
00484   else gui->set_mouse_pointer (wid, name, mask);
00485 }
00486 
00487 /******************************************************************************
00488 * Delayed messages
00489 ******************************************************************************/
00490 
00491 message_rep::message_rep (widget wid2, string s2, time_t t2):
00492   wid (wid2), s (s2), t (t2) {}
00493 message::message (widget wid, string s, time_t t):
00494   rep (tm_new<message_rep> (wid, s, t)) {}
00495 
00496 tm_ostream&
00497 operator << (tm_ostream& out, message m) {
00498   return out << "message " << m->s << " to " << m->wid
00499             << "at time " << m->t << "\n";
00500 }
00501 
00502 static list<message>
00503 insert_message (list<message> l, widget wid, string s, time_t cur, time_t t) {
00504   if (is_nil (l)) return list<message> (message (wid, s, t));
00505   time_t ref= l->item->t;
00506   if ((t-cur) <= (ref-cur)) return list<message> (message (wid, s, t), l);
00507   return list<message> (l->item, insert_message (l->next, wid, s, cur, t));
00508 }
00509 
00510 void
00511 x_window_rep::delayed_message (widget wid, string s, time_t delay) {
00512   time_t ct= texmacs_time ();
00513   the_gui->messages= insert_message (the_gui->messages, wid, s, ct, ct+ delay);
00514 }
00515 
00516 /******************************************************************************
00517 * Routines concerning regions in a window
00518 ******************************************************************************/
00519 
00520 void
00521 x_window_rep::translate (SI x1, SI y1, SI x2, SI y2, SI dx, SI dy) {
00522   SI X1= x1+ dx;
00523   SI Y2= y2+ dy;
00524   ren->decode (x1, y1);
00525   ren->decode (x2, y2);
00526   ren->decode (X1, Y2);
00527   dx= X1- x1;
00528   dy= Y2- y2;
00529 
00530   XEvent report;
00531   while (XCheckWindowEvent (dpy, win, ExposureMask, &report))
00532     gui->process_event (this, &report);
00533 
00534   rectangles region (rectangle (x1, y2, x2, y1));
00535   rectangles invalid_intern= invalid_regions & region;
00536   rectangles invalid_extern= invalid_regions - invalid_intern;
00537   invalid_intern = ::translate (invalid_intern, dx, dy) & region;
00538   invalid_regions= invalid_extern | invalid_intern;
00539 
00540   if (x1<x2 && y2<y1)
00541     XCopyArea (dpy, win, win, gc, x1, y2, x2-x1, y1-y2, X1, Y2);
00542 }
00543 
00544 void
00545 x_window_rep::invalidate (SI x1, SI y1, SI x2, SI y2) {
00546   ren->outer_round (x1, y1, x2, y2);
00547   ren->decode (x1, y1);
00548   ren->decode (x2, y2);
00549   invalidate_event (x1, y2, x2, y1);
00550 }
00551 
00552 bool
00553 x_window_rep::repainted () {
00554   return is_nil (invalid_regions);
00555 }
00556 
00557 /******************************************************************************
00558 * Interface
00559 ******************************************************************************/
00560 
00561 window
00562 popup_window (widget w, string name, SI min_w, SI min_h,
00563              SI def_w, SI def_h, SI max_w, SI max_h)
00564 {
00565   char* _name= as_charp (name);
00566   window win= tm_new<x_window_rep> (w, the_gui, (char*) NULL,
00567                                 min_w, min_h, def_w, def_h, max_w, max_h);
00568   tm_delete_array (_name);
00569   return win;
00570 }
00571 
00572 window
00573 plain_window (widget w, string name, SI min_w, SI min_h,
00574              SI def_w, SI def_h, SI max_w, SI max_h)
00575 {
00576   char* _name= as_charp (name);
00577   window win= tm_new<x_window_rep> (w, the_gui, _name,
00578                                 min_w, min_h, def_w, def_h, max_w, max_h);
00579   tm_delete_array (_name);
00580   return win;
00581 }