GToolkit
/* $Id$ */
/* Copyright (c) 2006-2020 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Graphics GToolkit */
/* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#include <stdlib.h>
#include <string.h>
#include "common.h"
/* GWindow */
/* private */
/* types */
struct _GWindow
{
GWidget * gwidget;
/* GWindow */
char * title;
bool decorated;
bool fullscreen;
bool resizable;
int width;
int height;
/* not portable */
Window window;
GLXContext context;
};
/* prototypes */
static void _gwindow_hide(GWindow * gwindow);
static void _gwindow_show(GWindow * gwindow);
/* public */
/* functions */
/* gwindow_new */
GWindow * gwindow_new(void)
{
Display * display;
XVisualInfo * visual;
GWindow * gwindow;
XSetWindowAttributes attr;
Atom a;
if((gwindow = malloc(sizeof(*gwindow))) == NULL)
return NULL; /* FIXME report */
if((gwindow->gwidget = gwidget_new()) == NULL)
{
free(gwindow);
return NULL;
}
gwidget_set_self(gwindow->gwidget, gwindow);
gwidget_set_handler(gwindow->gwidget, GWIDGET_HANDLER_HIDE,
_gwindow_hide);
gwidget_set_handler(gwindow->gwidget, GWIDGET_HANDLER_SHOW,
_gwindow_show);
gwindow->title = NULL;
gwindow->decorated = true;
gwindow->fullscreen = false;
gwindow->resizable = true;
gwindow->width = -1;
gwindow->height = -1;
display = gtoolkit_get_display();
visual = gtoolkit_get_visual();
attr.colormap = gtoolkit_get_colormap();
attr.border_pixel = 0;
attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
StructureNotifyMask;
gwindow->window = XCreateWindow(display,
RootWindow(display, visual->screen), 0, 0,
(gwindow->width > 0) ? gwindow->width : 200,
(gwindow->height > 0) ? gwindow->height : 200,
0, visual->depth, InputOutput, visual->visual,
CWBorderPixel | CWColormap | CWEventMask, &attr);
gwindow->context = glXCreateContext(display, visual, 0, GL_TRUE);
a = XInternAtom(display, "WM_DELETE_WINDOW", True);
XSetWMProtocols(display, gwindow->window, &a, 1);
gtoolkit_register_window(gwindow);
return gwindow;
}
/* gwindow_delete */
void gwindow_delete(GWindow * gwindow)
{
gtoolkit_deregister_window(gwindow);
glXDestroyContext(gtoolkit_get_display(), gwindow->context);
free(gwindow->title);
free(gwindow);
}
/* accessors */
/* gwindow_get_decorated */
bool gwindow_get_decorated(GWindow * gwindow)
{
return gwindow->decorated;
}
/* gwindow_get_modal */
bool gwindow_get_modal(GWindow * gwindow)
{
return false;
}
/* gwindow_get_resizable */
bool gwindow_get_resizable(GWindow * gwindow)
{
return gwindow->resizable;
}
/* gwindow_get_size */
void gwindow_get_size(GWindow * gwindow, int * width, int * height)
{
if(width != NULL)
*width = gwindow->width;
if(height != NULL)
*height = gwindow->height;
}
/* gwindow_get_title */
char const * gwindow_get_title(GWindow * gwindow)
{
return gwindow->title;
}
/* gwindow_get_window */
Window gwindow_get_window(GWindow * gwindow)
{
return gwindow->window;
}
/* gwindow_set_resizable */
void gwindow_set_resizable(GWindow * gwindow, bool resizable)
{
/* FIXME really implement */
gwindow->resizable = resizable;
}
/* gwindow_set_title */
void gwindow_set_title(GWindow * gwindow, char const * title)
{
Display * display;
display = gtoolkit_get_display();
free(gwindow->title);
title = (title != NULL) ? title : "(untitled)";
/* XXX ignore errors */
gwindow->title = strdup(title);
if(!gwindow->fullscreen)
XSetStandardProperties(display, gwindow->window, title, title,
None, NULL, 0, NULL);
}
/* useful */
/* gwindow_event_configure */
void gwindow_event_configure(GWindow * gwindow, XConfigureEvent * event)
{
unsigned int width;
unsigned int height;
if(event->width == gwindow->width
&& event->height == gwindow->height)
return;
if((gwindow->width = event->width) < 0)
width = 0;
if((gwindow->height = event->height) < 1)
height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
}
/* gwindow_event_expose */
void gwindow_event_expose(GWindow * gwindow, XExposeEvent * event)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
/* FIXME redraw the window */
glXSwapBuffers(event->display, gwindow->window);
}
/* gwindow_move */
void gwindow_move(GWindow * gwindow, int x, int y)
{
/* XXX may fail */
XMoveWindow(gtoolkit_get_display(), gwindow->window, x, y);
}
/* gwindow_present */
void gwindow_present(GWindow * gwindow)
{
XMapRaised(gtoolkit_get_display(), gwindow->window);
}
/* gwindow_resize */
void gwindow_resize(GWindow * gwindow, int width, int height)
{
/* XXX may fail */
XResizeWindow(gtoolkit_get_display(), gwindow->window,
(width > 0) ? width : 1, (height > 0) ? height : 1);
}
/* private */
/* functions */
/* gwindow_hide */
static void _gwindow_hide(GWindow * gwindow)
{
XUnmapWindow(gtoolkit_get_display(), gwindow->window);
}
/* gwindow_show */
static void _gwindow_show(GWindow * gwindow)
/* FIXME accept flags (focus...) */
{
Display * display;
display = gtoolkit_get_display();
XMapWindow(display, gwindow->window);
glXMakeCurrent(display, gwindow->window, gwindow->context);
}