Archived

This topic is now archived and is closed to further replies.

owl

X11: Resizing the window won't resize the GC? Why?

Recommended Posts

This is the sample source code. If you could g++ this and tell me what I am doing wrong I will apreciate. You'll need the X11 dev libs. Thank you.
     
   
#include <X11/Xlib.h>

#include <X11/Xutil.h>

#include <X11/Intrinsic.h>

#include <X11/Xos.h>

#include <X11/Xatom.h>

#include <X11/Xproto.h>

#include <X11/keysym.h>

#include <stdlib.h>

#include <stdio.h>

#include <iostream>

#include <malloc.h>

using namespace std;

#define MWM_HINTS_FUNCTIONS (1L << 0)

#define MWM_HINTS_DECORATIONS   (1L << 1)

#define MWM_HINTS_INPUT_MODE    (1L << 2)

#define MWM_HINTS_ALL           (MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS|MWM_HINTS_INPUT_MODE) 

#define MWM_FUNC_ALL        (1L << 0)

#define MWM_FUNC_RESIZE     (1L << 1)

#define MWM_FUNC_MOVE       (1L << 2)

#define MWM_FUNC_MINIMIZE   (1L << 3)

#define MWM_FUNC_MAXIMIZE   (1L << 4)

#define MWM_FUNC_CLOSE      (1L << 5) 

#define MWM_DECOR_ALL       (1L << 0)

#define MWM_DECOR_BORDER    (1L << 1)

#define MWM_DECOR_RESIZEH   (1L << 2)

#define MWM_DECOR_TITLE     (1L << 3)

#define MWM_DECOR_MENU      (1L << 4)

#define MWM_DECOR_MINIMIZE  (1L << 5)

#define MWM_DECOR_MAXIMIZE  (1L << 6) 

#define MWM_INPUT_MODELESS          0

#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1

#define MWM_INPUT_SYSTEM_MODAL          2

#define MWM_INPUT_FULL_APPLICATION_MODAL    3

Atom	   WM_DELETE_WINDOW;

Atom	   wmMotifHints;

Display*	m_pDisplay;
int			m_iScreenNum;
int			m_iDepth;
Visual*		m_pVisual;
Screen*		m_pScreen;
Window		m_Window;	
GC			m_GC;
bool		m_bRunning = false;
int			m_iWidth;
int			m_iHeight;

int main()
{
	cout << "-------------------------------------------------------------------.\n";
	cout << "-- APP INIT -------------------------------------------------------.\n";
	cout << "-------------------------------------------------------------------.\n";

	m_pDisplay = XOpenDisplay(NULL);
	m_iScreenNum = DefaultScreen(m_pDisplay);
	m_pScreen = DefaultScreenOfDisplay(m_pDisplay);
	m_pVisual = DefaultVisualOfScreen(m_pScreen);
	m_iDepth  = DefaultDepth(m_pDisplay, m_iScreenNum);
	
	XSetWindowAttributes swa;
	
    unsigned long 	 valuemask;
    
    valuemask = CWBackPixel; 
    swa.background_pixel = WhitePixel(m_pDisplay, m_iScreenNum);
    valuemask |= CWBitGravity;
	swa.bit_gravity = NorthWestGravity;
    valuemask |= CWBorderPixel;
	swa.border_pixel = 0;//BlackPixelOfScreen(m_pDisplay);

    valuemask |= CWColormap;
	swa.colormap = 0;//DefaultColormapOfScreen(m_pDisplay);

    valuemask |= CWCursor;
	swa.cursor = None;
    valuemask |= CWWinGravity;
	swa.win_gravity = NorthGravity;
    
    m_Window = XCreateWindow(m_pDisplay, XDefaultRootWindow(m_pDisplay), 
	0, 0, 300, 300,0,m_iDepth, InputOutput, 
	m_pVisual,valuemask, &swa);

	WM_DELETE_WINDOW = XInternAtom( m_pDisplay, "WM_DELETE_WINDOW", False);
	XSetWMProtocols (m_pDisplay, m_Window, &WM_DELETE_WINDOW, 1);
	
	wmMotifHints=XInternAtom(m_pDisplay,"_MOTIF_WM_HINTS",0);
//------------

	struct 
	{
		long flags;
    	long functions;
    	long decorations;
    	long inputmode;
	} prop;
  
	prop.flags=MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS|MWM_HINTS_INPUT_MODE;
	prop.decorations=0;

	prop.inputmode=MWM_INPUT_PRIMARY_APPLICATION_MODAL;
	
	prop.functions=MWM_FUNC_MOVE;
	prop.functions|=MWM_FUNC_RESIZE;
	
	prop.decorations|=MWM_DECOR_TITLE;
	prop.decorations|=MWM_DECOR_BORDER;
	prop.decorations|=MWM_DECOR_RESIZEH;
		
	prop.decorations|=MWM_DECOR_MINIMIZE;
	prop.functions|=MWM_FUNC_MINIMIZE;
	
	prop.decorations|=MWM_DECOR_MAXIMIZE;
	prop.functions|=MWM_FUNC_MAXIMIZE;
	
	prop.functions|=MWM_FUNC_CLOSE;
	
   XChangeProperty(m_pDisplay,m_Window,wmMotifHints,wmMotifHints,32,PropModeReplace,(unsigned char*)&prop,4);

//------------	

    
    XSelectInput(m_pDisplay, m_Window, 
    KeyPressMask           | KeyReleaseMask         | ButtonPressMask | 
    ButtonReleaseMask      | EnterWindowMask        | LeaveWindowMask | 
    PointerMotionMask      | PointerMotionHintMask  | Button1MotionMask | 
    Button2MotionMask      | Button3MotionMask      | Button4MotionMask |
    Button5MotionMask      | ButtonMotionMask       | KeymapStateMask | 
    ExposureMask           | VisibilityChangeMask   | StructureNotifyMask | 
    ResizeRedirectMask     | SubstructureNotifyMask | SubstructureRedirectMask | 
    FocusChangeMask        | PropertyChangeMask     | ColormapChangeMask | 
    OwnerGrabButtonMask);

	XWindowAttributes wa;
	XGetWindowAttributes(m_pDisplay, m_Window, &wa);
	m_iWidth = wa.width;
	m_iHeight = wa.height;
    
    cout <<"creating GC...\n";
	if (m_GC)
		XFree (m_GC);
	m_GC = 0;
    m_GC = XCreateGC(m_pDisplay,m_Window,0,NULL);
    if (m_GC<0) 
    {
		m_GC = 0;
		cout <<"Couln't create GC.\n";
		return 0;;
    }
	XMapWindow(m_pDisplay,m_Window);
    XSync(m_pDisplay,false);

	m_bRunning = true;
	
    XEvent event;

    while(m_bRunning)
	while (XPending(m_pDisplay))  
    {
		XNextEvent(m_pDisplay, &event);
		switch  (event.type) 
		{
			case Expose:   
				cout << "EXPOSE EVENT - DRAWING STUFF.\n";
				XWindowAttributes wa;
				XGetWindowAttributes(m_pDisplay, m_Window, &wa);
				cout << "Windows Attributes.\n"<<"   Width: "<<wa.width<<"\n"<<"  Height:"<<wa.height<<"\n";
				
				XSetForeground(m_pDisplay, m_GC, BlackPixel(m_pDisplay, m_iScreenNum));
				XSetBackground(m_pDisplay, m_GC, WhitePixel(m_pDisplay, m_iScreenNum));
				XSetLineAttributes(m_pDisplay, m_GC, 1/*width*/, LineSolid, CapButt, JoinBevel);
				XSetFillStyle(m_pDisplay, m_GC, FillSolid);

				XDrawRectangle(m_pDisplay, m_Window, m_GC, 0, 0, m_iWidth-2, m_iHeight-2);
				cout << "Expose Event Handled.\n";
			break;
			case MotionNotify:
				cout << "MotionNotify Event Handled.\n";
			break;
			case ButtonPress:
				cout << "ButtonPress Event Handled.\n";
			break;
			case ButtonRelease:
				cout << "ButtonRelease Event Handled.\n";
			break;
			case ColormapNotify:
				cout << "ColormapNotify Event Handled.\n";
			break;
			case EnterNotify:
				cout << "EnterNotify Event Handled.\n";
			break; 
			case LeaveNotify:
				cout << "LeaveNotify Event Handled.\n";
			break;
			case GraphicsExpose:
				cout << "GraphicsExpose Event Handled.\n";
			break;
			case NoExpose:
				cout << "NoExpose Event Handled.\n";
			break; 
			case FocusIn:
				cout << "FocusIn Event Handled.\n";
			break; 
			case FocusOut:
				cout << "FocusOut Event Handled.\n";
			break; 
			case KeymapNotify:
				cout << "KeymapNotify Event Handled.\n";
			break;
			case KeyPress:
				cout << "KeyPress Event Handled.\n";
			break; 
			case KeyRelease:
				cout << "KeyRelease Event Handled.\n";
			break; 
			case PropertyNotify:
				cout << "PropertyNotify Event Handled.\n";
			break; 
			case ResizeRequest:
			{
				m_iWidth = event.xresizerequest.width;
				m_iHeight = event.xresizerequest.height;
				cout << "ResizeRequest Event Handled.\n"<<"   New width: "<<event.xresizerequest.width<<"\n"<<"  New height:"<<event.xresizerequest.height<<"\n";
				
				//XResizeWindow(m_pDisplay, m_Window, m_iWidth, m_iHeight);

			}
			break; 
			case CirculateNotify:
				cout << "CirculateNotify Event Handled.\n";
			break; 
			case ConfigureNotify:
				cout << "ConfigureNotify Event Handled.\n";
			break; 
			case DestroyNotify:
				cout << "CWindow->Main: DestroyNotify handled. Closing.\n";
			m_bRunning=false;
			break; 
			case GravityNotify:
				cout << "GravityNotify Event Handled.\n";
			break; 
			case MapNotify:
				cout << "MapNotify Event Handled.\n";
			break; 
			case ReparentNotify:
				cout << "ReparentNotify Event Handled.\n";
			break; 
			case UnmapNotify:
				cout << "UnmapNotify Event Handled.\n";
			break; 
			case CreateNotify:
				cout << "CreateNotify Event Handled.\n";
			break; 
			case CirculateRequest:
				cout << "CirculateRequest Event Handled.\n";
			break; 
			case ConfigureRequest:
				cout << "ConfigureRequest Event Handled.\n";
			break; 
			case MapRequest:
				cout << "MapRequest Event Handled.\n";
			break; 
			case ClientMessage:
				if (event.xclient.data.l[0] == WM_DELETE_WINDOW) 
				{
					cout << "wm_delete_window HANDLED!!! VAMOS CARAJO!.\n";
					m_bRunning = false;
                }
				cout << "ClientMessage Event Handled.\n";
			break; 
			case MappingNotify:
				cout << "MappingNotify Event Handled.\n";
			break; 
			case SelectionClear:
				cout << "SelectionClear Event Handled.\n";
			break; 
			case SelectionNotify:
				cout << "SelectionNotify Event Handled.\n";
			break; 
			case SelectionRequest:
				cout << "SelectionRequest Event Handled.\n";
			break; 
			case VisibilityNotify:
				cout << "VisibilityNotify Event Handled.\n";
			break;
		}
    }
	if (m_GC)
		XFree (m_GC);
    XDestroyWindow(m_pDisplay, m_Window);
	XCloseDisplay(m_pDisplay);

}
     
Edit: Source Update 2. [edited by - xaxa on May 5, 2003 7:30:40 AM]

Share this post


Link to post
Share on other sites
I could be mean and say the reason it doesn''t work is because
you''re using something that looks suspiciously like motif in
your program (and motif is just wrong!).

However, the real reason is you''re expecting something which
won''t happen to happen. From the xlib manual:

"The function attributes of a GC are used when you update a section of a drawable (the destination) with bits from somewhere else (the source). The function in a GC defines how the new destination bits are to be computed from the source bits and the old destination bits."

When you resize the window, you draw nothing into it. The value
of the existing window contents is undefined. It may or may not
be black or any other colour pixel depending.

The "XSetBackground" sets the background colour WHEN USING the GC.
So it gets initially set when you create and map the window, but
since you don''t call any other functions in the main loop, when
you resize you get other random pixels in your window (not black).

To fix this you''ll have to catch the expose event (as you do)
and redraw something to the screen (eg. XFillRectangle). If
the window changes size you''ll have to catch the new size and
changes the appropriate arguments in your fill call (if you''re
drawing with a pixmap, yes, you have to re allocate the back
buffer when you resize: typically you allocate a standard size
and don''t make it smaller, only larger, except for gross changes
in the window size.)

Share this post


Link to post
Share on other sites
Ps. If you''d actually said what the problem was, not just posted the code it''d have been a lot easier to diagnose (I had to actually compile and play with it to see what your vague subject heading was talking about).

Share this post


Link to post
Share on other sites
quote:
Original post by Shadow Mint
I could be mean and say the reason it doesn't work is because
you're using something that looks suspiciously like motif in
your program (and motif is just wrong!).


I use the motif constants to change the window decorations (Max,min buttons). KDE and Gnome recognize them well.

quote:
Original post by Shadow Mint
However, the real reason is you're expecting something which
won't happen to happen. From the xlib manual:

"The function attributes of a GC are used when you update a section of a drawable (the destination) with bits from somewhere else (the source). The function in a GC defines how the new destination bits are to be computed from the source bits and the old destination bits."


This is exactly what isn't working. I updated the code so it draws a rectangle with the new size on every Expose event. But the GC isn't resized at all.

And even worst: the ResizeRequest event is passing the new values for the window, I log them so you can see them. Next I ask the values from the window and they don't change at all.

By the way, I'm using KDE and you?

[edited by - xaxa on May 5, 2003 7:24:34 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Shadow Mint
Ps. If you''d actually said what the problem was, not just posted the code it''d have been a lot easier to diagnose (I had to actually compile and play with it to see what your vague subject heading was talking about).


I thought the title of the topic was enough. I''m sorry, my english isn''t as good as I would like it to be.

Share this post


Link to post
Share on other sites
I see what you''re saying, I''m not sure. I''ll have to have a better look. It''s not all bad; the map state, etc. are ok and the resize event is working...

I''m not sure why the window attributes are not updates (or if they should be). More of a response later.

Share this post


Link to post
Share on other sites
I got it. If I SelectInput(ResizeRedirectMask), the gc doesn''t get resized. I don''t need it anyway because when the window change in some way ConfigureNotify is sent, I can update my size variables there by calling XGetWindowAttributes.

Thank you for you time Shadow, I hope this helps someone else.

Share this post


Link to post
Share on other sites
Glad you got it all sorted! I still can''t find any documentation
which supports this, but basically:

Xlib doesn''t keep any window state data. Once you''ve created it
the only sure way to get the window attributes is to catch the
events when it changes and manually keep track of them (if your
own structures).

I''d stay totally away from XGetWindowAttributes were I you; I''m
dubious about the data kept there; the xlib state updates can be
tricky to work out because of the server-client model.

ciao!

Share this post


Link to post
Share on other sites
Actually I changed that. Now I get the info from the width and height members of configurenotify event.

I'm working on a portable application library, just for fun. I just started.
Some screenshot of a window with tree working buttons in kde and windoze:

Edit: I'm making all the controls from scratch.



[edited by - xaxa on May 6, 2003 11:48:25 PM]

Share this post


Link to post
Share on other sites