1 /* aguix.h
2  * This file belongs to Worker, a file manager for UN*X/X11.
3  * Copyright (C) 2001-2020 Ralf Hoffmann.
4  * You can contact me at: ralf@boomerangsworld.de
5  *   or http://www.boomerangsworld.de/worker
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #ifndef AGUIX_H
23 #define AGUIX_H
24 
25 #include "aguixdefs.h"
26 #include "lowlevelfunc.h"
27 #include "message.h"
28 #include "util.h"
29 #include "refcount.hh"
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36 #include <X11/keysym.h>
37 #include <X11/cursorfont.h>
38 #include <X11/Xatom.h>
39 
40 #ifdef HAVE_XFT
41 #include <X11/Xft/Xft.h>
42 #endif
43 
44 #include <map>
45 #include <list>
46 #include <atomic>
47 #include <memory>
48 
49 #include "aguixfont.hh"
50 #include "aguixcolor.hh"
51 #include "backgroundmessagehandler.hh"
52 
53 #include "faces.hh"
54 
55 class AWindow;
56 class PopUpWindow;
57 class BubbleWindow;
58 class TimeoutStore;
59 
60 enum {MES_WAIT,MES_GET};
61 enum {NON_GADGET,CLOSE_GADGET,BUTTON_GADGET,SHADOW_GADGET,CHOOSE_GADGET,LISTVIEW,ONELVC,MORELVC,STRING_GADGET};
62 
63 struct AGUIX_XProperty {
AGUIX_XPropertyAGUIX_XProperty64     AGUIX_XProperty() : success( true ),
65                         property_data( NULL ),
66                         type( None ),
67                         format( 0 ),
68                         number_of_items( 0 )
69     {}
70 
freePropertyAGUIX_XProperty71     void freeProperty()
72     {
73         if ( property_data ) {
74             XFree( property_data );
75             property_data = NULL;
76         }
77     }
78 
79     bool success;
80     unsigned char *property_data;
81     Atom type;
82 	int format;
83 	unsigned long number_of_items;
84 };
85 
86 class AGUIX {
87 public:
88   AGUIX( int argc, char **argv, const std::string &classname );
89   ~AGUIX();
90   AGUIX( const AGUIX &other );
91   AGUIX &operator=( const AGUIX &other );
92 
93   int initX();
94   int checkX();
95   void closeX();
96   int getDepth() const;
97   Colormap getColormap() const;
98   Display *getDisplay() const;
99   int getScreen() const;
100   void panic(const char *);
101   void setFG( const AGUIXColor &color );
102   void setBG( const AGUIXColor &color );
103   void setFG( GC gc, const AGUIXColor &color );
104   void setBG( GC gc, const AGUIXColor &color );
105   int getCharHeight() const;
106   void FillRectangle(Drawable buffer,int x,int y,int w,int h);
107   void DrawText( class DrawableCont &dc, const char *text, int x, int y, const AGUIXColor &color );
108   void DrawLine(Drawable buffer,int px1,int py1,int px2,int py2);
109   void DrawPoint(Drawable buffer,int x,int y);
110   void FillRectangle(Drawable buffer,GC gc,int x,int y,int w,int h);
111   void DrawText( class DrawableCont &dc, AGUIXFont *, const char *text, int x, int y, const AGUIXColor &color );
112   void DrawLine(Drawable buffer,GC gc,int px1,int py1,int px2,int py2);
113   void DrawPoint(Drawable buffer,GC gc,int x,int y);
114 
115   void DrawTriangleFilled(Drawable buffer, int px1, int py1, int px2, int py2, int px3, int py3);
116   void DrawTriangleFilled(Drawable buffer, GC tgc, int px1, int py1, int px2, int py2, int px3, int py3);
117   void setClip( AGUIXFont *font, class DrawableCont *dc, int x, int y, int width, int height );
118   void unclip( AGUIXFont *font, class DrawableCont *dc );
119 
120   void ClearWin(Window win);
121   void SetWindowBG( Window win, const AGUIXColor &color );
122   int getFontBaseline() const;
123   AGUIXColor AddColor( int red, int green, int blue, AGUIXColor::color_type_t type = AGUIXColor::USER_COLOR );
124   void freeColors();
125   int changeColor( const AGUIXColor &index, int red, int green ,int blue );
126   int getNumberOfColorsForType( AGUIXColor::color_type_t type ) const;
127   unsigned long getPixel( const AGUIXColor &color ) const;
128 #ifdef HAVE_XFT
129   XftColor *getColBufEntry( const AGUIXColor &color );
130 #else
131   unsigned long getColBufEntry( const AGUIXColor &color );
132 #endif
133 
134     typedef struct _col_values_t {
_col_values_t_col_values_t135         _col_values_t() : red( 0 ),
136                           green( 0 ),
137                           blue( 0 )
138         {}
_col_values_t_col_values_t139         _col_values_t( int r, int g, int b) : red( r ),
140                                               green( g ),
141                                               blue( b )
142         {}
143 
144         bool operator==( const _col_values_t &rhs )
145         {
146             if ( red == rhs.red &&
147                  green == rhs.green &&
148                  blue == rhs.blue ) {
149                 return true;
150             } else {
151                 return false;
152             }
153         }
154 
155         int red, green, blue;
156     } col_values_t;
157 
158     col_values_t getColorInfo( const AGUIXColor &color ) const;
159     col_values_t blend( const col_values_t &lhs,
160                         const col_values_t &rhs,
161                         int percentage ) const;
162 
163     AGUIXColor getColor( const col_values_t &v );
164 
165   std::string getClassname() const;
166   Atom *getCloseAtom();
167   void insertWindow( AWindow *win, bool change_transient = false );
168   void removeWindow(AWindow *win);
169   AGMessage *GetMessage(AWindow *parent);
170   AGMessage *WaitMessage(AWindow *parent);
171   void ReplyMessage(AGMessage *);
172   Message *wait4mess( int mode );
173   void copyArea(Drawable source,Drawable dest,int s_x,int s_y,int width,int height,int d_x,int d_y);
174   void Flush();
175   int getargc() const;
176   char **getargv() const;
177   void putAGMsg(AGMessage *msg);
178   AGMessage *getAGMsg();
179   void WindowtoFront(Window);
180   void WindowtoBack(Window);
181   AGUIXFont *getFont( const char* );
182   int setFont( const char* );
183   void ExposeHandler(Message*);
184   AWindow *findAWindow(Window);
185   char *getNameOfKey(KeySym,unsigned int) const;
186   Window getGroupWin() const;
187   int queryPointer(Window win,int *x,int *y);
188   int queryRootPointer(int *x,int *y);
189   int queryPointer(Window win,int *x,int *y,unsigned int *buttons);
190   void setCursor(Window win,int type);
191   void unsetCursor(Window win);
192 
193   enum {WAIT_CURSOR=0,SCROLLH_CURSOR,SCROLLV_CURSOR,MAXCURSORS};
194   int startCut(GUIElement *elem,const char *buffer);
195   void cancelCut();
196   int startPaste(GUIElement *elem);
197   bool amiOwner() const;
198   const char *getCutBuffer() const;
199     void requestCut( Window win, bool fallback = false );
200     bool rerequestCut();
201   void cancelCutPaste(GUIElement *elem);
202   bool isDoubleClick(struct timeval *t1,struct timeval *t2) const;
203   bool isDoubleClick( Time t1, Time t2 ) const;
204 
205   static int scaleElementsW( int wantedWidth,
206 			     int borderwidth,
207 			     int minSpace,
208 			     int maxSpace,
209 			     bool allowShrink,
210 			     bool allowStretch,
211 			     GUIElement **elem,
212 			     int *minWidths,
213 			     int nr );
214   static int centerElementsY( GUIElement *element,
215 			      GUIElement *center2element );
216   int getRootWindowWidth() const;
217   int getRootWindowHeight() const;
218 
219   Pixmap createPixmap( Drawable d, int width, int height );
220   void freePixmap( Pixmap p );
221 
222   void DrawDottedLine( Drawable buffer, int px1, int py1, int px2, int py2 );
223   void DrawDottedRectangle( Drawable buffer, int x, int y, int w, int h );
224   void setDottedFG( const AGUIXColor &color );
225 
226   void DrawDashXorLine( Drawable buffer, int px1, int py1, int px2, int py2 );
227   void DrawDashXorRectangle( Drawable buffer, int x, int y, int w, int h );
228 
229   void DrawDashDLine( Drawable buffer, int px1, int py1, int px2, int py2 );
230   void DrawDashDRectangle( Drawable buffer, int x, int y, int w, int h );
231   void setDashDFG( const AGUIXColor &color );
232   void setDashDBG( const AGUIXColor &color );
233 
234   static bool isModifier( KeySym key );
235   static char *getStringForKeySym( KeySym key );
236   static KeySym getKeySymForString( const char *str1 );
237   void rebuildBackgroundPixmap();
238   void setWindowBackgroundPixmap( Window win );
239   void doXMsgs( AWindow *parent, bool onlyexpose );
240   void doXMsgs( int mode, AWindow *parent, bool onlyexpose );
241   bool noMoreMessages() const;
242 #ifdef USE_XIM
243   XIMStyle getXIMStyle() const;
244   XIM getXIM() const;
245   void IMInstCallback( Display *calldsp );
246   void IMDestCallback();
247 #endif
248   void setTransientWindow( AWindow *twin = NULL );
249   const AWindow* getTransientWindow() const;
250   KeySym getLastKeyRelease();
251   unsigned int getLastMouseRelease();
252   void msgLock( Widget *e );
253   void msgUnlock( const Widget *e );
254   bool msgHoldsLock( const Widget *e );
255   void enableTimer();
256   void disableTimer();
257 
258   int getTextWidth( const char *str, AGUIXFont *font = NULL );
259   int getTextWidth( const char *str, AGUIXFont *font, int len );
260   int getStrlen4Width( const char *str, int width, int *return_width, AGUIXFont *font = NULL );
261 
262   /**
263    *
264    * @param str
265    * @param maxlen  use not more then len bytes (or <0 for strlen)
266    */
267   int getStrlen4WidthMaxlen( const char *str, int maxlen,
268                              int width, int *return_width, AGUIXFont *font = NULL );
269 
270     static std::atomic< long > timerEvent;
271 
272   void drawBorder( Drawable buffer, GC usegc, bool pressed, int x, int y, int w, int h, int topright_space );
273   void drawBorder( Drawable buffer, bool pressed, int x, int y, int w, int h, int topright_space );
274 
275     typedef enum { CLOSE_ATOM, NET_WM_NAME_ATOM, NET_WM_ICON_NAME_ATOM, TARGETS_ATOM,
276                    NET_WM_WINDOW_TYPE, NET_WM_WINDOW_TYPE_DIALOG, NET_WM_WINDOW_TYPE_NORMAL,
277                    UTF8_STRING, NET_WM_STATE, NET_WM_STATE_MAXIMIZED_HORZ,
278                    NET_WM_STATE_MAXIMIZED_VERT,
279                    XDNDENTER,
280                    XDNDPOSITION,
281                    XDNDSTATUS,
282                    XDNDTYPELIST,
283                    XDNDACTIONCOPY,
284                    XDNDDROP,
285                    XDNDLEAVE,
286                    XDNDFINISHED,
287                    XDNDSELECTION,
288                    XDNDPROXY,
289                    XDNDAWARE,
290                    CARDINAL_ATOM,
291                    NET_WM_ICON_ATOM
292     } atom_name_t;
293   Atom getAtom( atom_name_t name ) const;
294 
295   void registerPopUpWindow( PopUpWindow *win );
296   void hidePopUpWindows( int group_id = -1 );
297   void hideOtherPopUpWindows( int group_id = -1 );
298   void popupOpened();
299   void popupClosed();
300 
301   void xSync();
302 
303   int getWidgetRootPosition( Widget *widget, int *x, int *y );
304   bool getLastTypedWindowEvent( Window win, int type, XEvent *return_event );
305   int addDefaultColors();
306 
307     AWindow *getFocusedAWindow();
308 
309     void registerBGHandler( AWindow *window, const RefCount< BackgroundMessageHandler > &handler );
310     void unregisterBGHandler( AWindow *window );
311     void executeBGHandlers( AGMessage &msg );
312     void destroyBGHandlers();
313 
314     void copyToClipboard( const std::string &s );
315 
316     /**
317      * return the location and dimension of the largest (xinerama) screen
318      * under the mouse
319      */
320     void getLargestDimensionOfCurrentScreen( int *x, int *y,
321                                              int *width, int *height );
322 
323     void setApplyWindowDialogType( bool nv );
324     bool getApplyWindowDialogType() const;
325 
326     void setOverrideXIM( bool nv );
327     bool getOverrideXIM() const;
328 
329     void setSkipFilterEvent( bool nv );
330 
331     void applyFaces( const FaceDB &faces );
getFaces()332     const FaceDB &getFaces() const
333     {
334         return m_faces;
335     }
336 
getFaceCol_default_fg()337     int getFaceCol_default_fg() const
338     {
339         return m_default_fg;
340     }
341 
getFaceCol_default_bg()342     int getFaceCol_default_bg() const
343     {
344         return m_default_bg;
345     }
346 
getFaceCol_3d_bright()347     int getFaceCol_3d_bright() const
348     {
349         return m_3d_bright;
350     }
351 
getFaceCol_3d_dark()352     int getFaceCol_3d_dark() const
353     {
354         return m_3d_dark;
355     }
356 
357     void setBubbleHelpWindow( std::shared_ptr< BubbleWindow > bw );
358     void setBubbleHelpCandidate( GUIElement *elem );
359     void clearBubbleHelpCandidate( GUIElement *elem = NULL);
360 
361     void setExternalTimeoutStore( std::weak_ptr< TimeoutStore > timeout_store );
362 
363     void external_timeout_callback();
364 
365     bool isValidScreenPosition( int x, int y,
366                                 int w, int h );
367 
368     void startXDND( Widget *initiator,
369                     Window w,
370                     unsigned int mouse_button );
371 
372     void widgetDestroyed( Widget *w );
373 
374     int getCurrentUserColorInstance() const;
375 
376     bool isModifierPressed( unsigned int mask );
377 
378     void setStandardIconData( const unsigned long *data,
379                               size_t data_length );
380     bool getStandardIconData( const unsigned long **return_data,
381                               size_t *return_data_length ) const;
382 private:
383   Display *dsp;
384   int scr;
385   Colormap cmap;
386   GC gc, dotted_gc, dashxor_gc, dashdouble_gc;
387   Atom WM_delete_window,
388       XA_NET_WM_NAME,
389       XA_NET_WM_ICON_NAME,
390       XA_TARGETS,
391       XA_NET_WM_WINDOW_TYPE,
392       XA_NET_WM_WINDOW_TYPE_DIALOG,
393       XA_NET_WM_WINDOW_TYPE_NORMAL,
394       XA_UTF8_STRING,
395       XA_NET_WM_STATE,
396       XA_NET_WM_STATE_MAXIMIZED_HORZ,
397       XA_NET_WM_STATE_MAXIMIZED_VERT,
398       XA_XDNDENTER,
399       XA_XDNDPOSITION,
400       XA_XDNDSTATUS,
401       XA_XDNDTYPELIST,
402       XA_XDNDACTIONCOPY,
403       XA_XDNDDROP,
404       XA_XDNDLEAVE,
405       XA_XDNDFINISHED,
406       XA_XDNDSELECTION,
407       XA_XDNDPROXY,
408       XA_XDNDAWARE,
409       XA_MULTIPLE,
410       XA_TEXT_URI_LIST,
411       XA_TEXT_PLAIN,
412       XA_NET_WM_ICON,
413       XA_CARDINAL_ATOM;
414 
415   int m_argc;
416   char **m_argv;
417   std::string m_classname;
418   unsigned long white,black;
419   AGUIXFont *mainfont;
420   int initOK;
421   int CharHeight;
422 #ifdef HAVE_XFT
423   XftColor m_user_col_buf[256];
424   XftColor m_system_col_buf[16];
425     std::vector< XftColor > m_extra_col_buf;
426 #else
427   unsigned long m_user_col_buf[256];
428   unsigned long m_system_col_buf[16];
429     std::vector< unsigned long > m_extra_col_buf;
430 #endif
431     int m_user_colors, m_system_colors, m_extra_colors;
432 
433   std::map< AGUIXColor, col_values_t, AGUIXColor::compare_func > m_color_values;
434 
435   XEvent LastEvent;
436   std::list<AWindow*> wins;
437   typedef std::list<AWindow*>::const_iterator wins_cit_t;
438   typedef std::list<AWindow*>::iterator wins_it_t;
439 
440   std::list<AGMessage*> messages;
441   typedef std::list<AGMessage*>::const_iterator agmessage_list_cit_t;
442   typedef std::list<AGMessage*>::iterator agmessage_list_it_t;
443 
444   std::list<AGUIXFont*> fonts;
445   typedef std::list<AGUIXFont*>::const_iterator aguixfont_list_cit_t;
446   typedef std::list<AGUIXFont*>::iterator aguixfont_list_it_t;
447 
448   std::list<PopUpWindow*> popup_wins;
449   typedef std::list<PopUpWindow*>::const_iterator popup_wins_cit_t;
450   typedef std::list<PopUpWindow*>::iterator popup_wins_it_t;
451 
452   std::list<AWindow*> wins_as_transient_for;
453 
454   Window groupwin;
455   void createGroupWin();
456   void destroyGroupWin();
457 
458   bool ReactMessage(Message*,AWindow*);
459   void buildAGMessage( Message *agmsg );
460 
461   bool privatecmap;
462   void changeColormap();
463   void updateSystemColors( int changed_user_color );
464 
465   Cursor cursors[MAXCURSORS];
466   GUIElement *cutstart,*pastestart;
467 
468   unsigned int rootWindowWidth, rootWindowHeight;
469   Pixmap backpm;
470 #ifdef USE_XIM
471   XIM inputmethod;
472   XIMStyle im_style;
473 
474   int openIM();
475   void closeIM();
476 #endif
477   char *keybuf;
478   int keybuf_len;
479 
480   AWindow *transientwindow;
481   KeySym lastkeyrelease;
482   unsigned int lastmouserelease;
483 
484   Widget *msgLockElement;
485   bool timerEnabled;
486 #ifndef USE_AGUIXTIMER
487   struct timeval timerStart;
488 #endif
489   int msgHandler( int mode, AWindow *parent, bool onlyExpose );
490   enum { TIMER_TICKS = 25 }; //HARDCODED
491   long lastTimerEventNr;
492 
493   void checkPopUpWindows( Message * );
494 
495   bool waitForEventOnFD( int ms );
496 
497     AGUIX_XProperty getProperty( Window win,
498                                  Atom property );
499     Atom selectBestTargetForDND( Atom type1,
500                                  Atom type2,
501                                  Atom type3 );
502     Atom selectBestTargetForDND( AGUIX_XProperty type_list );
503     Atom selectBestTargetForDND( const std::vector< Atom > &list );
504 
505     void handleXDNDEnter( XEvent *e );
506     void handleXDNDPosition( XEvent *e );
507     void handleXDNDLeave( XEvent *e );
508     void handleXDNDDrop( XEvent *e );
509     void handleXDNDStatus( XEvent *e );
510     void handleXDNDFinished( XEvent *e );
511     void cleanupDND();
512 
513     void initXDNDTypes();
514 
515     void processSelectionRequest( XEvent *e );
516     void setTargetsProperty( Window w, Atom property );
517     Window findXDNDAwareWindow( Window w, Window *return_proxy_window );
518 
519   int m_open_popup_counter;
520   bool m_popup_ignore_button_release;
521 
522   Window m_current_xfocus_window;
523 
524     /* background handler for some window */
525     std::map< AWindow *, RefCount< BackgroundMessageHandler > > m_bg_handlers;
526 
527     /* temporary list for unregister to cleanup handler after execution */
528     std::list< RefCount< BackgroundMessageHandler > > m_bg_handler_cleanup_list;
529     std::list< AWindow *> m_bg_handler_erase_handler;
530 
531     std::string clipboard_string;
532 
533     Atom m_last_selection_request_atom;
534     Window m_last_selection_request_window;
535 
536     bool m_apply_window_dialog_type;
537 
538     bool m_override_xim;
539     bool m_skip_filter_event;
540 
541     int m_filtered_key_events_in_a_row;
542 
543     FaceDB m_faces;
544 
545     int m_default_fg;
546     int m_default_bg;
547     int m_3d_bright;
548     int m_3d_dark;
549 
550     struct bubble_help_data {
bubble_help_databubble_help_data551         bubble_help_data() : help_candidate( NULL ),
552                              enter_time{ 0, 0 }
553         {}
554         std::shared_ptr< BubbleWindow > bubble_help_window;
555         GUIElement *help_candidate;
556         struct timeval enter_time;
557     } m_bubble_help;
558 
559     time_t now;
560 
561     struct aguix_timeouts {
aguix_timeoutsaguix_timeouts562         aguix_timeouts() : timeout_set( false )
563         {}
564 
~aguix_timeoutsaguix_timeouts565         ~aguix_timeouts()
566         {
567             disableExternalTimer();
568         }
569 
570         std::weak_ptr< TimeoutStore > timeout_store;
571         bool timeout_set;
572 
573         void enableExternalTimer();
574         void disableExternalTimer();
575     } m_external_timeouts;
576 
577     struct aguix_xdnd_state {
aguix_xdnd_stateaguix_xdnd_state578         aguix_xdnd_state() : drop_active( false ),
579                              source( None ),
580                              selected_target( None ),
581                              last_activity( 0 ),
582                              version( 0 ),
583                              target_awin( NULL ),
584                              sent_target_request( false ),
585                              target_widget( NULL ),
586                              drag_active( false ),
587                              drag_target_status( AGUIX_XDND_UNAWARE ),
588                              drag_initiator( NULL ),
589                              drag_initiator_window( None ),
590                              drag_current_target_window( None ),
591                              drag_current_target_version( -1 ),
592                              drag_current_proxy_target_window( None ),
593                              drag_selection_pending( false ),
594                              drop_issued( false ),
595                              mouse_button( Button1 ),
596                              position_silent( false ),
597                              position_silent_x( 0 ),
598                              position_silent_y( 0 ),
599                              position_silent_w( 0 ),
600                              position_silent_h( 0 )
601         {}
602 
603         enum xdnd_target_status {
604             AGUIX_XDND_UNAWARE,
605             AGUIX_XDND_UNRESPONSIVE,
606             AGUIX_XDND_ACCEPT
607         };
608 
609         bool drop_active;
610         Window source;
611         Atom selected_target;
612         time_t last_activity;
613         int version;
614         AWindow *target_awin;
615         bool sent_target_request;
616         Widget *target_widget;
617 
618         bool drag_active;
619         enum xdnd_target_status drag_target_status;
620         Widget *drag_initiator;
621         Window drag_initiator_window;
622         Window drag_current_target_window;
623         int drag_current_target_version;
624 
625         Window drag_current_proxy_target_window;
626 
627         bool drag_selection_pending;
628         bool drop_issued;
629 
630         unsigned int mouse_button;
631 
632         bool position_silent;
633         int position_silent_x;
634         int position_silent_y;
635         int position_silent_w;
636         int position_silent_h;
637     }  m_xdnd;
638 
639     std::map< std::string, int > m_xdnd_receive_types;
640 
641     Cursor m_xcursor_plus;
642     Cursor m_xcursor_circle;
643 
644     int m_x_fd;
645 
646     int m_user_color_instance;
647 
648     unsigned int m_modifier_pressed = 0;
649 
650     const unsigned long *m_net_wm_icon_data = NULL;
651     size_t m_net_wm_icon_data_length = 0;
652 };
653 
654 #endif
655 
656 /* Local Variables: */
657 /* mode:c++ */
658 /* End: */
659