Back to index

texmacs  1.0.7.15
edit_interface.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : edit_interface.cpp
00004 * DESCRIPTION: interface between the editor and the window manager
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 "Interface/edit_interface.hpp"
00013 #include "file.hpp"
00014 #include "convert.hpp"
00015 #include "server.hpp"
00016 #include "tm_window.hpp"
00017 #include "Metafont/tex_files.hpp"
00018 #include "data_cache.hpp"
00019 #include "drd_mode.hpp"
00020 #include "message.hpp"
00021 #include "tree_traverse.hpp"
00022 #ifdef EXPERIMENTAL
00023 #include "../../Style/Evaluate/evaluate_main.hpp"
00024 #endif
00025 
00026 extern void (*env_next_prog)(void);
00027 
00028 /*static*/ string
00029 MODE_LANGUAGE (string mode) {
00030   if (mode == "text") return LANGUAGE;
00031   else if (mode == "math") return MATH_LANGUAGE;
00032   else if (mode == "prog") return PROG_LANGUAGE;
00033   else if (mode == "src") return LANGUAGE;
00034   cerr << "Mode = " << mode << "\n";
00035   FAILED ("invalid mode");
00036   return LANGUAGE;
00037 }
00038 
00039 /******************************************************************************
00040 * Main edit_interface routines
00041 ******************************************************************************/
00042 
00043 edit_interface_rep::edit_interface_rep ():
00044   env_change (0),
00045   last_change (texmacs_time()), last_update (last_change-1),
00046   do_animate (false), next_animate (last_change-1),
00047   full_screen (false), got_focus (false),
00048   sh_s (""), sh_mark (0), pre_edit_s (""), pre_edit_mark (0),
00049   popup_win (),
00050   message_l (""), message_r (""), last_l (""), last_r (""),
00051   sfactor (sv->get_default_shrinking_factor ()),
00052   pixel (sfactor*PIXEL), copy_always (),
00053   last_x (0), last_y (0), last_t (0),
00054   made_selection (false), table_selection (false),
00055   oc (0, 0), temp_invalid_cursor (false),
00056   shadow (NULL), stored (NULL),
00057   cur_sb (2), cur_wb (2)
00058 {
00059   input_mode= INPUT_NORMAL;
00060   gui_root_extents (cur_wx, cur_wy);
00061 }
00062 
00063 edit_interface_rep::~edit_interface_rep () {
00064   if (is_attached (this)) {
00065     renderer ren= get_renderer (this);
00066     ren->delete_shadow (shadow);
00067     ren->delete_shadow (stored);
00068   }
00069 }
00070 
00071 edit_interface_rep::operator tree () {
00072   return tuple ("editor", as_string (get_name ()));
00073 }
00074 
00075 void
00076 edit_interface_rep::suspend () {
00077   if (got_focus) {
00078     interrupt_shortcut ();
00079     set_message ("", "", false);
00080   }
00081   got_focus= false;
00082   notify_change (THE_FOCUS);
00083   if (is_attached (this)) {
00084     renderer ren= get_renderer (this);
00085     ren->delete_shadow (shadow);
00086     ren->delete_shadow (stored);
00087   }
00088 }
00089 
00090 void
00091 edit_interface_rep::resume () {
00092   got_focus= true;
00093   SERVER (menu_main ("(horizontal (link texmacs-menu))"));
00094   SERVER (menu_icons (0, "(horizontal (link texmacs-main-icons))"));
00095   SERVER (menu_icons (1, "(horizontal (link texmacs-mode-icons))"));
00096   SERVER (menu_icons (2, "(horizontal (link texmacs-focus-icons))"));
00097   SERVER (menu_icons (3, "(horizontal (link texmacs-extra-icons))"));
00098   if (use_side_tools)
00099     { SERVER (side_tools (0, "(vertical (link texmacs-side-tools))")); }
00100   cur_sb= 2;
00101   tp= make_cursor_accessible (tp, true);
00102   notify_change (THE_FOCUS + THE_EXTENTS + THE_CURSOR);
00103 }
00104 
00105 /******************************************************************************
00106 * Routines for dealing with shrinked coordinates
00107 ******************************************************************************/
00108 
00109 int
00110 edit_interface_rep::get_pixel_size () {
00111   return pixel;
00112 }
00113 
00114 void
00115 edit_interface_rep::set_shrinking_factor (int sf) {
00116   if (sfactor != sf) {
00117     sfactor= sf;
00118     pixel  = sf*PIXEL;
00119     init_env (SFACTOR, as_string (sf));
00120     notify_change (THE_ENVIRONMENT);
00121   }
00122 }
00123 
00124 void
00125 edit_interface_rep::invalidate (SI x1, SI y1, SI x2, SI y2) {
00126   send_invalidate (this, (x1-sfactor+1)/sfactor, (y1-sfactor+1)/sfactor,
00127                        (x2+sfactor-1)/sfactor, (y2+sfactor-1)/sfactor);
00128 }
00129 
00130 void
00131 edit_interface_rep::invalidate (rectangles rs) {
00132   while (!is_nil (rs)) {
00133     invalidate (rs->item->x1-pixel, rs->item->y1-pixel,
00134               rs->item->x2+pixel, rs->item->y2+pixel);
00135     rs= rs->next;
00136   }
00137 }
00138 
00139 void
00140 edit_interface_rep::update_visible () {
00141   SERVER (get_visible (vx1, vy1, vx2, vy2));
00142   vx1 *= sfactor; vy1 *= sfactor; vx2 *= sfactor; vy2 *= sfactor;
00143 }
00144 
00145 SI
00146 edit_interface_rep::get_window_height () {
00147   update_visible ();
00148   return vy2 - vy1;
00149 }
00150 
00151 void
00152 edit_interface_rep::scroll_to (SI x, SI y) {
00153   stored_rects= rectangles ();
00154   copy_always = rectangles ();
00155   SERVER (scroll_to (x/sfactor, y/sfactor));
00156 }
00157 
00158 void
00159 edit_interface_rep::set_extents (SI x1, SI y1, SI x2, SI y2) {
00160   stored_rects= rectangles ();
00161   copy_always = rectangles ();
00162   SERVER (set_extents ((x1-sfactor+1)/sfactor, (y1-sfactor+1)/sfactor,
00163                      (x2+sfactor-1)/sfactor, (y2+sfactor-1)/sfactor));
00164 }
00165 
00166 /******************************************************************************
00167 * Scroll so as to make the cursor and the selection visible
00168 ******************************************************************************/
00169 
00170 void
00171 edit_interface_rep::cursor_visible () {
00172   path sp= find_innermost_scroll (eb, tp);
00173   cursor cu= get_cursor ();
00174   if (is_nil (sp)) {
00175     update_visible ();
00176     cu->y1 -= 2*pixel; cu->y2 += 2*pixel;
00177     if ((cu->ox+ ((SI) (cu->y1 * cu->slope)) <  vx1) ||
00178        (cu->ox+ ((SI) (cu->y2 * cu->slope)) >= vx2) ||
00179        (cu->oy+ cu->y1 <  vy1) ||
00180        (cu->oy+ cu->y2 >= vy2))
00181       {
00182        scroll_to (cu->ox- ((vx2-vx1)>>1), cu->oy+ ((vy2-vy1)>>1));
00183        send_invalidate_all (this);
00184       }
00185   }
00186   else {
00187     SI x, y, sx, sy;
00188     rectangle outer, inner;
00189     find_canvas_info (eb, sp, x, y, sx, sy, outer, inner);
00190     if ((cu->ox+ ((SI) (cu->y1 * cu->slope)) < x + outer->x1) ||
00191        (cu->ox+ ((SI) (cu->y2 * cu->slope)) > x + outer->x2))
00192       {
00193        SI tx= inner->x2 - inner->x1;
00194        SI cx= outer->x2 - outer->x1;
00195        if (tx > cx) {
00196          SI outer_cx= cu->ox - x;
00197          SI inner_cx= outer_cx - sx;
00198          SI dx= inner_cx - inner->x1;
00199          double p= 100.0 * ((double) (dx - (cx>>1))) / ((double) (tx-cx));
00200          p= max (min (p, 100.0), 0.0);
00201          tree old_xt= eb[path_up (sp)]->get_info ("scroll-x");
00202          tree new_xt= as_string (p) * "%";
00203          if (new_xt != old_xt && is_accessible (obtain_ip (old_xt))) {
00204            object fun= symbol_object ("tree-set");
00205            object cmd= list_object (fun, old_xt, new_xt);
00206            exec_delayed (scheme_cmd (cmd));
00207            temp_invalid_cursor= true;
00208          }
00209        }
00210       }
00211     if ((cu->oy+ cu->y1 < y + outer->y1) ||
00212        (cu->oy+ cu->y2 > y + outer->y2))
00213       {
00214        SI ty= inner->y2 - inner->y1;
00215        SI cy= outer->y2 - outer->y1;
00216        if (ty > cy) {
00217          SI outer_cy= cu->oy + ((cu->y1 + cu->y2) >> 1) - y;
00218          SI inner_cy= outer_cy - sy;
00219          SI dy= inner_cy - inner->y1;
00220          double p= 100.0 * ((double) (dy - (cy>>1))) / ((double) (ty-cy));
00221          p= max (min (p, 100.0), 0.0);
00222          tree old_yt= eb[path_up (sp)]->get_info ("scroll-y");
00223          tree new_yt= as_string (p) * "%";
00224          if (new_yt != old_yt && is_accessible (obtain_ip (old_yt))) {
00225            object fun= symbol_object ("tree-set");
00226            object cmd= list_object (fun, old_yt, new_yt);
00227            exec_delayed (scheme_cmd (cmd));
00228            temp_invalid_cursor= true;
00229          }
00230        }
00231       }
00232   }
00233 }
00234 
00235 void
00236 edit_interface_rep::selection_visible () {
00237   update_visible ();
00238   if ((vx2 - vx1 <= 80*pixel) || (vy2 - vy1 <= 80*pixel)) return;
00239 
00240   SI extra= (cur_sb == 1? 20 * pixel: 0);
00241   bool scroll_x= (end_x < vx1 + extra) || (end_x >= vx2 - extra);
00242   bool scroll_y= (end_y < vy1 + extra) || (end_y >= vy2 - extra);
00243   SI new_x= vx1;
00244   if (scroll_x) new_x= end_x - ((vx2-vx1)>>1);
00245   SI new_y= vy2;
00246   if (scroll_y) new_y= end_y + ((vy2-vy1)>>1);
00247 
00248   if (scroll_x || scroll_y) {
00249     scroll_to (new_x, new_y);
00250     send_invalidate_all (this);
00251     SI old_vx1= vx1, old_vy1= vy1;
00252     update_visible ();
00253     end_x += vx1- old_vx1;
00254     end_y += vy1- old_vy1;
00255   }
00256 }
00257 
00258 /******************************************************************************
00259 * Computation of environment rectangles
00260 ******************************************************************************/
00261 
00262 static bool
00263 is_graphical (tree t) {
00264   return
00265     is_func (t, _POINT) ||
00266     is_func (t, LINE) || is_func (t, CLINE) ||
00267     is_func (t, ARC) || is_func (t, CARC) ||
00268     is_func (t, SPLINE) || is_func (t, CSPLINE);
00269 }
00270 
00271 static void
00272 correct_adjacent (rectangles& rs1, rectangles& rs2) {
00273   if (N(rs1) != 1 || N(rs2) != 1) return;
00274   SI bot1= rs1->item->y1;
00275   SI top2= rs2->item->y2;
00276   if (rs1->item->y1 <= rs2->item->y1) {
00277     //cout << "Discard " << rs1->item->y1 << ", " << rs2->item->y1 << "\n";
00278     return;
00279   }
00280   if (rs1->item->y2 <= rs2->item->y2) {
00281     //cout << "Discard " << rs1->item->y2 << ", " << rs2->item->y2 << "\n";
00282     return;
00283   }
00284   SI mid= (bot1 + top2) >> 1;
00285   rs1->item->y1= mid;
00286   rs2->item->y2= mid;
00287 }
00288 
00289 void
00290 edit_interface_rep::compute_env_rects (path p, rectangles& rs, bool recurse) {
00291   if (p == rp) return;
00292   tree st= subtree (et, p);
00293   if ((is_func (st, TABLE) || is_func (st, SUBTABLE)) &&
00294       recurse && get_preference ("show table cells") == "on") {
00295     rectangles rl;
00296     for (int i=0; i<N(st); i++) {
00297       if (is_func (st[i], ROW))
00298         for (int j=0; j<N(st[i]); j++) {
00299           selection sel= eb->find_check_selection (p*i*j*0, p*i*j*1);
00300           rectangles rsel= copy (thicken (sel->rs, 0, 2 * pixel));
00301           if (i > 0 && is_func (st[i-1], ROW) && j < N(st[i-1])) {
00302             selection bis= eb->find_check_selection (p*(i-1)*j*0, p*(i-1)*j*1);
00303             rectangles rbis= copy (thicken (bis->rs, 0, 2 * pixel));
00304             correct_adjacent (rbis, rsel);
00305           }
00306           if (i+1 < N(st) && is_func (st[i+1], ROW) && j < N(st[i+1])) {
00307             selection bis= eb->find_check_selection (p*(i+1)*j*0, p*(i+1)*j*1);
00308             rectangles rbis= copy (thicken (bis->rs, 0, 2 * pixel));
00309             correct_adjacent (rsel, rbis);
00310           }
00311           rectangles selp= thicken (rsel,  pixel/2,  pixel/2);
00312           rectangles selm= thicken (rsel, -pixel/2, -pixel/2);
00313           rl << simplify (::correct (selp - selm));
00314         }
00315     }
00316     rs << simplify (rl);
00317     if (recurse) compute_env_rects (path_up (p), rs, recurse);
00318   }
00319   else if (is_atomic (st) ||
00320            drd->is_child_enforcing (st) ||
00321            //is_document (st) || is_concat (st) ||
00322            is_func (st, TABLE) || is_func (st, SUBTABLE) ||
00323            is_func (st, ROW) || is_func (st, TFORMAT) ||
00324            is_graphical (st) ||
00325            (is_func (st, WITH) && is_graphical (st[N(st)-1])) ||
00326            (is_func (st, WITH) && is_graphical_text (st[N(st)-1])) ||
00327            (is_compound (st, "math", 1) &&
00328             is_compound (subtree (et, path_up (p)), "input")))
00329     compute_env_rects (path_up (p), rs, recurse);
00330   else {
00331     int new_mode= DRD_ACCESS_NORMAL;
00332     if (get_init_string (MODE) == "src") new_mode= DRD_ACCESS_SOURCE;
00333     int old_mode= set_access_mode (new_mode);
00334     tree st= subtree (et, p);
00335     if (is_accessible_cursor (et, p * right_index (st)) || in_source ()) {
00336       bool right;
00337       path p1= p * 0, p2= p * 1, q1, q2;
00338       if (is_script (subtree (et, p), right)) {
00339        p1= start (et, p * 0);
00340        p2= end   (et, p * 0);
00341       }
00342       if (is_func (st, CELL)) { q1= p1; q2= p2; }
00343       else selection_correct (p1, p2, q1, q2);
00344       selection sel= eb->find_check_selection (q1, q2);
00345       if (N(focus_get ()) >= N(p))
00346         if (!recurse || get_preference ("show full context") == "on")
00347           rs << outline (sel->rs, pixel);
00348     }
00349     set_access_mode (old_mode);
00350     if (recurse || N(rs) == 0)
00351       compute_env_rects (path_up (p), rs, recurse);
00352   }
00353 }
00354 
00355 /******************************************************************************
00356 * handling changes
00357 ******************************************************************************/
00358 
00359 void
00360 edit_interface_rep::notify_change (int change) {
00361   env_change= env_change | change;
00362   needs_update ();
00363   if ((change & (THE_TREE | THE_SELECTION | THE_CURSOR)) != 0)
00364     manual_focus_set (path (), (change & THE_TREE) != 0);
00365 }
00366 
00367 bool
00368 edit_interface_rep::has_changed (int question) {
00369   return (env_change & question) != 0;
00370 }
00371 
00372 int
00373 edit_interface_rep::idle_time (int event_type) {
00374   if (env_change == 0 &&
00375       get_renderer (this) -> repainted () &&
00376       (!check_event (event_type)) &&
00377       got_focus)
00378     return texmacs_time () - last_change;
00379   else return 0;
00380 }
00381 
00382 int
00383 edit_interface_rep::change_time () {
00384   return last_change;
00385 }
00386 
00387 void
00388 edit_interface_rep::apply_changes () {
00389   //cout << "Apply changes\n";
00390   //cout << "et= " << et << "\n";
00391   //cout << "tp= " << tp << "\n";
00392   //cout << HRULE << "\n";
00393   if (env_change == 0) {
00394     if (last_change-last_update > 0 &&
00395         idle_time (INTERRUPTED_EVENT) >= 1000/6)
00396     {
00397       SERVER (menu_main ("(horizontal (link texmacs-menu))"));
00398       SERVER (menu_icons (0, "(horizontal (link texmacs-main-icons))"));
00399       SERVER (menu_icons (1, "(horizontal (link texmacs-mode-icons))"));
00400       SERVER (menu_icons (2, "(horizontal (link texmacs-focus-icons))"));
00401       SERVER (menu_icons (3, "(horizontal (link texmacs-extra-icons))"));
00402       if (use_side_tools)
00403         { SERVER (side_tools (0, "(vertical (link texmacs-side-tools))")); }
00404       set_footer ();
00405       if (!get_renderer (this) -> interrupted ()) drd_update ();
00406       cache_memorize ();
00407       last_update= last_change;
00408     }
00409     return;
00410   }
00411   
00412   // cout << "Applying changes " << env_change << " to " << get_name() << "\n";
00413   // time_t t1= texmacs_time ();
00414   
00415   // cout << "Always\n";
00416   update_visible ();
00417   
00418   // cout << "Handling automatic resizing\n";
00419   int sb= 1;
00420   if (is_attached (this) &&
00421       get_server() -> has_window() &&
00422       get_init_string (PAGE_MEDIUM) == "automatic")
00423     {
00424       SI wx, wy;
00425       if (cvw == NULL) ::get_size (get_window (this), wx, wy);
00426       else ::get_size (widget (cvw), wx, wy);
00427       if (get_init_string (SCROLL_BARS) == "false") sb= 0;
00428       if (get_server () -> in_full_screen_mode ()) sb= 0;
00429 #ifdef QTTEXMACS
00430       if (sb) wx -= 24 * PIXEL;
00431 #else
00432       if (sb) wx -= 20 * PIXEL;
00433 #endif
00434       if (wx != cur_wx || wy != cur_wy) {
00435        cur_wx= wx; cur_wy= wy;
00436        init_env (PAGE_SCREEN_WIDTH, as_string (wx*sfactor) * "tmpt");
00437        init_env (PAGE_SCREEN_HEIGHT, as_string (wy*sfactor) * "tmpt");
00438        notify_change (THE_ENVIRONMENT);
00439       }
00440     }
00441   if (sb != cur_sb) {
00442     cur_sb= sb;
00443     if (get_server() -> has_window()) {
00444       tm_window win= get_server () -> get_window ();
00445       win -> set_scrollbars (sb);
00446     }
00447   }
00448   
00449   // window decorations (menu bar, icon bars, footer)
00450   int wb= 2;
00451   if (is_attached (this)) {
00452     string val= get_init_string (WINDOW_BARS);
00453     if (val == "auto") wb= 2;
00454     else if (val == "false") wb= 0;
00455     else if (val == "true") wb= 1;
00456     if (wb != cur_wb) {
00457       cur_wb= wb;
00458       if (wb != 2) {
00459         get_server () -> show_header (wb);
00460         get_server () -> show_footer (wb);
00461       }
00462     }
00463   }
00464   
00465   // cout << "Handling selection\n";
00466   if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_SELECTION)) {
00467     if (made_selection) {
00468       invalidate (selection_rects);
00469       if (!selection_active_any ()) {
00470         made_selection= false;
00471         set_selection (tp, tp);
00472         selection_rects= rectangles ();
00473       }
00474     }
00475   }
00476   
00477   // cout << "Handling environment\n";
00478   if (env_change & THE_ENVIRONMENT)
00479     typeset_invalidate_all ();
00480 
00481   // cout << "Handling tree\n";
00482   if (env_change & (THE_TREE+THE_ENVIRONMENT)) {
00483     typeset_invalidate_env ();
00484     SI x1, y1, x2, y2;
00485     typeset (x1, y1, x2, y2);
00486     invalidate (x1- 2*pixel, y1- 2*pixel, x2+ 2*pixel, y2+ 2*pixel);
00487     // check_data_integrety ();
00488     the_ghost_cursor()= eb->find_check_cursor (tp);
00489   }
00490   
00491 #ifdef EXPERIMENTAL
00492   if (env_change & THE_ENVIRONMENT)
00493     environment_update ();
00494   if (env_change & THE_TREE) {
00495     cout << HRULE;
00496     mem= evaluate (ste, cct);
00497     tree rew= mem->get_tree ();
00498     cout << HRULE;
00499     cout << tree_to_texmacs (rew) << LF;
00500     //print_tree (rew);
00501   }
00502 #endif
00503   
00504   // cout << "Handling extents\n";
00505   if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_EXTENTS))
00506     set_extents (eb->x1, eb->y1, eb->x2, eb->y2);
00507   
00508   // cout << "Cursor\n";
00509   temp_invalid_cursor= false;
00510   if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_EXTENTS+
00511                     THE_CURSOR+THE_SELECTION+THE_FOCUS)) {
00512     SI /*P1= pixel,*/ P2= 2*pixel, P3= 3*pixel;
00513     int THE_CURSOR_BAK= env_change & THE_CURSOR;
00514     go_to_here ();
00515     env_change= (env_change & (~THE_CURSOR)) | THE_CURSOR_BAK;
00516     if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_EXTENTS+THE_CURSOR))
00517       if (!inside_active_graphics ())
00518         cursor_visible ();
00519     
00520     cursor cu= get_cursor();
00521     rectangle ocr (oc->ox+ ((SI) (oc->y1*oc->slope))- P3, oc->oy+ oc->y1- P3,
00522                    oc->ox+ ((SI) (oc->y2*oc->slope))+ P2, oc->oy+ oc->y2+ P3);
00523     copy_always= rectangles (ocr, copy_always);
00524     invalidate (ocr->x1, ocr->y1, ocr->x2, ocr->y2);
00525     rectangle ncr (cu->ox+ ((SI) (cu->y1*cu->slope))- P3, cu->oy+ cu->y1- P3,
00526                    cu->ox+ ((SI) (cu->y2*cu->slope))+ P2, cu->oy+ cu->y2+ P3);
00527     invalidate (ncr->x1, ncr->y1, ncr->x2, ncr->y2);
00528     copy_always= rectangles (ncr, copy_always);
00529     oc= copy (cu);
00530    
00531     // set hot spot in the gui
00532     send_cursor (this, (cu->ox-sfactor+1)/sfactor, (cu->oy-sfactor+1)/sfactor);
00533 
00534     path sp= selection_get_cursor_path ();
00535     bool semantic_flag= semantic_active (path_up (sp));
00536     bool full_context= (get_preference ("show full context") == "on");
00537     bool table_cells= (get_preference ("show table cells") == "on");
00538     bool show_focus= (get_preference ("show focus") == "on");
00539     bool semantic_only= (get_preference ("show only semantic focus") == "on");
00540     rectangles old_env_rects= env_rects;
00541     rectangles old_foc_rects= foc_rects;
00542     env_rects= rectangles ();
00543     foc_rects= rectangles ();
00544     path pp= path_up (tp);
00545     tree pt= subtree (et, pp);
00546     if (none_accessible (pt));
00547     else pp= path_up (pp);
00548     if (full_context || table_cells)
00549       compute_env_rects (pp, env_rects, true);
00550     if (show_focus && (!semantic_flag || !semantic_only))
00551       compute_env_rects (pp, foc_rects, false);
00552     if (env_rects != old_env_rects) {
00553       invalidate (old_env_rects);
00554       invalidate (env_rects);
00555     }
00556     else if (env_change & THE_FOCUS) invalidate (env_rects);
00557     if (foc_rects != old_foc_rects) {
00558       invalidate (old_foc_rects);
00559       invalidate (foc_rects);
00560     }
00561     else if (env_change & THE_FOCUS) invalidate (foc_rects);
00562     
00563     rectangles old_sem_rects= sem_rects;
00564     bool old_sem_correct= sem_correct;
00565     sem_rects= rectangles ();
00566     sem_correct= true;
00567     if (semantic_flag && show_focus) {
00568       path sp= selection_get_cursor_path ();
00569       path p1= tp, p2= tp;
00570       if (selection_active_any ()) selection_get (p1, p2);
00571       sem_correct= semantic_select (path_up (sp), p1, p2, 2);
00572       if (!sem_correct) {
00573         path sr= semantic_root (path_up (sp));
00574         p1= start (et, sr);
00575         p2= end (et, sr);
00576       }
00577       path q1, q2;
00578       selection_correct (p1, p2, q1, q2);
00579       selection sel= eb->find_check_selection (q1, q2);
00580       sem_rects << outline (sel->rs, pixel);
00581     }
00582     if (sem_rects != old_sem_rects || sem_correct != old_sem_correct) {
00583       invalidate (old_sem_rects);
00584       invalidate (sem_rects);
00585     }
00586     else if (env_change & THE_FOCUS) invalidate (sem_rects);
00587     
00588     invalidate_graphical_object ();
00589   }
00590   
00591   // cout << "Handling selection\n";
00592   if (env_change & THE_SELECTION) {
00593     made_selection= selection_active_any ();
00594     if (made_selection) {
00595       table_selection= selection_active_table ();
00596       selection sel; selection_get (sel);
00597       rectangles rs= thicken (sel->rs, pixel, 3*pixel);
00598 #ifndef QTTEXMACS
00599       rs= simplify (::correct (rs - thicken (rs, -pixel, -pixel)));
00600 #endif
00601       selection_rects= rs;
00602       invalidate (selection_rects);
00603     }
00604   }
00605   
00606   // cout << "Handling locus highlighting\n";
00607   if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_EXTENTS))
00608     update_active_loci ();
00609   if (env_change & THE_LOCUS) {
00610     if (locus_new_rects != locus_rects) {
00611       invalidate (locus_rects);
00612       invalidate (locus_new_rects);
00613       locus_rects= locus_new_rects;
00614     }
00615   }
00616   
00617   // cout << "Handling backing store\n";
00618   if (!is_nil (stored_rects)) {
00619     if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_SELECTION+THE_EXTENTS))
00620       stored_rects= rectangles ();
00621   }
00622   if (inside_active_graphics ()) {
00623     SI gx1, gy1, gx2, gy2;
00624     if (find_graphical_region (gx1, gy1, gx2, gy2)) {
00625       rectangle gr= rectangle (gx1, gy1, gx2, gy2);
00626       if (!is_nil (gr - stored_rects))
00627         invalidate (gx1, gy1, gx2, gy2);
00628     }
00629   }
00630   
00631   // cout << "Handling environment changes\n";
00632   if (env_change & THE_ENVIRONMENT)
00633     send_invalidate_all (this);
00634   
00635   // cout << "Applied changes\n";
00636   // time_t t2= texmacs_time ();
00637   // if (t2 - t1 >= 10) cout << "apply_changes took " << t2-t1 << "ms\n";
00638   env_change  = 0;
00639   last_change = texmacs_time ();
00640   last_update = last_change-1;
00641   manual_focus_release ();
00642 }
00643 
00644 /******************************************************************************
00645 * Animations
00646 ******************************************************************************/
00647 
00648 void
00649 edit_interface_rep::animate () {
00650   // cout << do_animate << ", " << next_animate << "\n";
00651   if (do_animate && texmacs_time () - next_animate >= 0) {
00652     bool flag= false;
00653     time_t at= 0;
00654     rectangles rs;
00655     eb->anim_get_invalid (flag, at, rs);
00656     if (flag && texmacs_time () - at >= 0)
00657       invalidate (rs);
00658     do_animate  = flag;
00659     next_animate= at;
00660   }
00661 }
00662 
00663 /******************************************************************************
00664 * Miscellaneous routines
00665 ******************************************************************************/
00666 
00667 void
00668 edit_interface_rep::full_screen_mode (bool flag) {
00669   full_screen= flag;
00670   send_invalidate_all (this);
00671 }
00672 
00673 void
00674 edit_interface_rep::before_menu_action () {
00675   archive_state ();
00676   start_editing ();
00677   set_input_normal ();
00678 }
00679 
00680 void
00681 edit_interface_rep::after_menu_action () {
00682   notify_change (THE_DECORATIONS);
00683   end_editing ();
00684   windows_delayed_refresh (1);
00685 }
00686 
00687 rectangle
00688 edit_interface_rep::get_window_extents () {
00689   SI ox, oy, w, h;
00690   widget me= ::get_canvas (widget (cvw));
00691   ::get_position (me, ox, oy);
00692   ::get_size (me, w, h);
00693   SI vx1, vy1, vx2, vy2;
00694   SERVER (get_visible (vx1, vy1, vx2, vy2));
00695   ox -= vx1; oy -= vy2;
00696   return rectangle (ox, oy - h, ox + w, oy);
00697 }
00698 
00699 cursor
00700 edit_interface_rep::search_cursor (path p) {
00701   return eb->find_check_cursor (p);
00702 }
00703 
00704 selection
00705 edit_interface_rep::search_selection (path start, path end) {
00706   selection sel= eb->find_check_selection (start, end);
00707   rectangle r= least_upper_bound (sel->rs) / 5;
00708   return sel;
00709 }
00710 
00711 /******************************************************************************
00712 * event handlers
00713 ******************************************************************************/
00714 
00715 void
00716 edit_interface_rep::handle_get_size_hint (SI& w, SI& h) {
00717   gui_root_extents (w, h);
00718 }
00719 
00720 void
00721 edit_interface_rep::handle_notify_resize (SI w, SI h) {
00722   (void) w; (void) h;
00723   notify_change (THE_TREE);
00724 }
00725 
00726 void
00727 edit_interface_rep::handle_set_shrinking_factor (int sf) {
00728   set_shrinking_factor (sf);
00729 }